[Pkg-javascript-commits] [node-mocha] 04/10: Imported Upstream version 2.2.5
Leo Iannacone
l3on-guest at moszumanska.debian.org
Sat May 30 15:58:24 UTC 2015
This is an automated email from the git hooks/post-receive script.
l3on-guest pushed a commit to branch master
in repository node-mocha.
commit aeb656ee3cdf0494032c2737a9d675fb7a9a065b
Author: Leo Iannacone <info at leoiannacone.com>
Date: Sat May 30 17:25:26 2015 +0200
Imported Upstream version 2.2.5
---
.editorconfig | 18 +
.mailmap | 1 +
.travis.yml | 16 +-
CONTRIBUTING.md | 49 +
History.md => HISTORY.md | 144 ++-
LICENSE | 2 +-
Makefile | 53 +-
README.md | 11 +
Readme.md | 203 ----
bin/_mocha | 112 +-
bin/mocha | 26 +-
bin/options.js | 36 +
bower.json | 30 +-
component.json | 14 +-
index.js | 3 +-
lib/browser/debug.js | 1 -
lib/browser/escape-string-regexp.js | 8 +-
lib/browser/events.js | 3 +-
lib/browser/progress.js | 12 +-
lib/browser/tty.js | 1 -
lib/context.js | 13 +-
lib/hook.js | 1 -
lib/interfaces/bdd.js | 39 +-
lib/interfaces/common.js | 58 ++
lib/interfaces/exports.js | 1 -
lib/interfaces/index.js | 1 -
lib/interfaces/qunit.js | 45 +-
lib/interfaces/tdd.js | 46 +-
lib/mocha.js | 69 +-
lib/pending.js | 16 +
lib/reporters/base.js | 57 +-
lib/reporters/doc.js | 1 -
lib/reporters/dot.js | 3 +-
lib/reporters/html-cov.js | 3 +-
lib/reporters/html.js | 24 +-
lib/reporters/index.js | 1 -
lib/reporters/json-cov.js | 1 -
lib/reporters/json-stream.js | 7 +-
lib/reporters/json.js | 1 -
lib/reporters/landing.js | 7 +-
lib/reporters/list.js | 1 -
lib/reporters/markdown.js | 21 +-
lib/reporters/min.js | 1 -
lib/reporters/nyan.js | 26 +-
lib/reporters/spec.js | 7 +-
lib/reporters/tap.js | 1 -
lib/reporters/templates/menu.jade | 2 +-
lib/reporters/templates/style.html | 8 +-
lib/reporters/xunit.js | 51 +-
lib/runnable.js | 32 +-
lib/runner.js | 119 ++-
lib/suite.js | 15 +-
lib/test.js | 1 -
lib/utils.js | 408 +++++++-
media/logo.svg | 3 +-
mocha.js | 1093 ++++++++++++++------
package.json | 28 +-
support/compile.js | 1 -
support/foot.js | 2 +-
support/tail.js | 3 +-
test.js | 9 +
test/acceptance/context.js | 1 -
test/acceptance/diffs.js | 87 --
test/acceptance/duration.js | 1 -
test/acceptance/failing/timeout.js | 17 -
test/acceptance/fs.js | 1 -
test/acceptance/glob/glob.js | 1 -
test/acceptance/globals.js | 1 -
test/acceptance/http.js | 3 +-
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 | 10 -
test/acceptance/misc/bail.js | 21 -
test/acceptance/misc/cascade.js | 58 --
test/acceptance/misc/exit.js | 5 +
test/acceptance/misc/grep.js | 22 -
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 | 16 -
test/acceptance/pending.js | 4 -
test/acceptance/require/require.js | 1 -
test/acceptance/root.js | 3 +-
test/acceptance/test.coffee | 2 +-
test/acceptance/throw.js | 111 ++
test/acceptance/timeout.js | 1 -
test/acceptance/uncaught.js | 17 -
test/acceptance/utils.js | 278 ++++-
test/browser/grep.html | 51 +
test/browser/grep.js | 108 ++
test/browser/large.js | 3 +-
test/browser/stack-trace.html | 24 +
test/browser/stack-trace.js | 20 +
test/color.js | 17 +
test/grep.js | 18 +-
test/hook.async.js | 1 -
test/hook.err.js | 6 +-
test/hook.sync.js | 3 +-
test/hook.sync.nested.js | 1 -
test/hook.timeout.js | 3 +-
test/http.meta.2.js | 19 +-
test/http.meta.js | 23 +-
test/integration/diffs.js | 45 +
test/integration/fixtures/cascade.js | 57 +
.../fixtures/diffs/diffs.css.in} | 2 +-
.../fixtures/diffs/diffs.css.out} | 2 +-
test/integration/fixtures/diffs/diffs.js | 84 ++
test/integration/fixtures/diffs/output | 91 ++
test/integration/fixtures/multiple.done.js | 18 +
.../fixtures/options/async-only.async.js | 3 +
.../fixtures/options/async-only.sync.js | 1 +
test/integration/fixtures/options/bail.js | 25 +
test/integration/fixtures/options/delay.js | 19 +
test/integration/fixtures/options/grep.js | 12 +
.../fixtures/options/sort.alpha.js} | 2 +-
.../fixtures/options/sort.beta.js} | 2 +-
.../fixtures/pending/skip.sync.before.js | 13 +
.../fixtures/pending/skip.sync.beforeEach.js | 13 +
.../integration/fixtures/pending/skip.sync.spec.js | 10 +
test/integration/fixtures/pending/spec.js | 3 +
test/integration/fixtures/regression/issue-1327.js | 15 +
test/integration/fixtures/timeout.js | 17 +
test/integration/fixtures/uncaught.hook.js | 15 +
test/integration/fixtures/uncaught.js | 26 +
test/integration/helpers.js | 142 +++
test/integration/hooks.js | 44 +
test/integration/multiple.done.js | 28 +
test/integration/options.js | 140 +++
test/integration/pending.js | 63 ++
test/integration/regression.js | 24 +
test/integration/timeout.js | 18 +
test/integration/uncaught.js | 37 +
test/jsapi/index.js | 2 -
test/mocha.js | 33 +
test/ms.js | 82 ++
test/regression/issue1327/case.js | 14 -
test/regression/issue1327/control.js | 10 -
test/reporters/base.js | 178 +++-
test/reporters/json.js | 7 +-
test/reporters/nyan.js | 2 +-
test/runnable.js | 6 +-
test/runner.js | 101 +-
test/suite.js | 1 -
test/utils.js | 150 ++-
148 files changed, 4139 insertions(+), 1363 deletions(-)
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..e3a4859
--- /dev/null
+++ b/.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/.mailmap b/.mailmap
new file mode 100644
index 0000000..7040131
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1 @@
+TJ Holowaychuk <tj at vision-media.ca>
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index ed05f88..2789c51 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,14 @@
language: node_js
+script: travis_retry npm test
node_js:
- - "0.11"
- - "0.10"
- - "0.8"
- - "0.6"
+- 'iojs'
+- '0.12'
+- '0.11'
+- '0.10'
+- '0.8'
+sudo: false
+notifications:
+ urls:
+ - secure: "EmycFlk48bUvOQ07mxnbcn6T+n3G4wVWuXgrDsUUp6EhJ9866wQK9i+qVhqogWuSEQrGoVaS/vpc/NEYxDP30BD/+nqgvOhVhLVEgtziI85imyV/oUVpArdW3AUmuzCrx7rQCivygjpBmWV9ZcUT5Km4qp1iQhuumy2WbplxrZ4="
+ on_success: change
+ on_failure: always
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..6d172f0
--- /dev/null
+++ b/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 ju [...]
+
+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/History.md b/HISTORY.md
similarity index 79%
rename from History.md
rename to HISTORY.md
index 9a63be6..9f7db23 100644
--- a/History.md
+++ b/HISTORY.md
@@ -1,4 +1,146 @@
+2.2.5 / 2015-05-14
+==================
+
+ * Merge pull request #1699 from nylen/upgrade/jsdiff
+ * Upgrade jsdiff to v1.4.0
+ * Merge pull request #1648 from nylen/fix/diff-colors
+ * Merge pull request #1686 from danielstjules/1327-regression
+ * Sanity check: update fixtures/regression/issue-1327.js to be closer to orig test
+ * Fix diff colors
+ * Merge pull request #1675 from danielstjules/integration-tests
+ * Merge pull request #1682 from kemitchell/spdx-license
+ * use a valid SPDX license identifier
+ * Add integration tests
+ * Merge pull request #1655 from a8m/fix-issue-1241
+ * Merge pull request #1661 from a8m/fix-issue-1660
+ * fix(utils/stringify): fix issue #1660
+ * fix(reporter/base): issue #1241
+
+2.2.4 / 2015-04-08
+==================
+
+ * Load mocha.opts in _mocha for now (close #1645)
+
+2.2.3 / 2015-04-07
+==================
+
+ * fix(reporter/base): string diff - issue #1241
+ * fix(reporter/base): string diff - issue #1241
+ * fix(reporter/base): don't show diffs for errors without expectation
+ * fix(reporter/base): don't assume error message is first line of stack
+ * improve: dry up reporter/base test
+ * fix(reporter/base): explicitly ignore showDiff #1614
+ * Add iojs to travis build
+ * Pass `--allow-natives-syntax` flag to node.
+ * Support --harmony_classes flag for io.js
+ * Fix 1556: Update utils.clean to handle newlines in func declarations
+ * Fix 1606: fix err handling in IE <= 8 and non-ES5 browsers
+ * Fix 1585: make _mocha executable again
+ * chore(package.json): add a8m as a contributor
+ * Fixed broken link on html-cov reporter
+ * support --es_staging flag
+ * fix issue where menu overlaps content.
+ * update contributors in package.json
+ * Remove trailing whitespace from reporter output
+ * Remove contributors list from readme
+ * log third-party reporter errors
+ * [Fix] Exclude not own properties when looping on options
+ * fix: support node args in mocha.opts (close #1573)
+ * fix(reporter/base): string diff - issue #1241
+
+2.2.1 / 2015-03-09
+==================
+
+ * Fix passing of args intended for node/iojs.
+
+2.2.0 / 2015-03-06
+==================
+
+ * Update mocha.js
+ * Add --fgrep. Use grep for RegExp, fgrep for str
+ * Ignore async global errors after spec resolution
+ * Fixing errors that prevent mocha.js from loading in the browser - fixes #1558
+ * fix(utils): issue #1558 + make
+ * add ability to delay root suite; closes #362, closes #1124
+ * fix insanity in http tests
+ * update travis: add node 0.12, add gitter, remove slack
+ * building
+ * resolve #1548: ensure the environment's "node" executable is used
+ * reporters/base: use supports-color to detect colorable term
+ * travis: use docker containers
+ * small fix: commander option for --expose-gc
+ * Ignore asynchronous errors after global failure
+ * Improve error output when a test fails with a non-error
+ * updated travis badge, uses svg instead of img
+ * Allow skip from test context for #332
+ * [JSHINT] Unnecessary semicolon fixed in bin/_mocha
+ * Added a reminder about the done() callback to test timeout error messages
+ * fixes #1496, in Mocha.run(fn), check if fn exists before executing it, added tests too
+ * Add Harmony Proxy flag for iojs
+ * test(utils|ms|*): test existing units
+ * add support for some iojs flags
+ * fix(utils.stringify): issue #1229, diff viewer
+ * Remove slack link
+ * Prevent multiple 'grep=' querystring params in html reporter
+ * Use grep as regexp (close #1381)
+ * utils.stringify should handle objects without an Object prototype
+ * in runnable test, comparing to undefined error's message rather than a literal
+ * Fix test running output truncation on async STDIO
+ * ammended for deprecated customFds option in child_process
+
+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
==================
@@ -17,7 +159,7 @@
* 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: timeout(0) will work at suite level (#1300)
* Fix for --watch+only() issue (#888 )
* fix: respect err.showDiff, add Base reporter test (#810)
diff --git a/LICENSE b/LICENSE
index 1c5d7fa..ca47f26 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
(The MIT License)
-Copyright (c) 2011-2014 TJ Holowaychuk <tj at vision-media.ca>
+Copyright (c) 2011-2015 TJ Holowaychuk <tj at 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/Makefile b/Makefile
index 72c4814..cde1648 100644
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ lib-cov:
test: test-unit
-test-all: test-bdd test-tdd test-qunit test-exports test-unit test-grep test-jsapi test-compilers test-sort test-glob test-requires test-reporters test-only test-failing test-regression
+test-all: test-bdd test-tdd test-qunit test-exports test-unit test-integration test-jsapi test-compilers test-glob test-requires test-reporters test-only
test-jsapi:
@node test/jsapi
@@ -48,25 +48,10 @@ test-unit:
--growl \
test/*.js
-test-regression: test-outputs/issue1327/case-out.json
+test-integration:
@./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/integration/*.js
test-compilers:
@./bin/mocha \
@@ -109,31 +94,6 @@ test-exports:
--ui exports \
test/acceptance/interfaces/exports
-test-grep:
- @./bin/mocha \
- --reporter $(REPORTER) \
- --grep fast \
- test/acceptance/misc/grep
-
-test-invert:
- @./bin/mocha \
- --reporter $(REPORTER) \
- --grep slow \
- --invert \
- test/acceptance/misc/grep
-
-test-bail:
- @./bin/mocha \
- --reporter $(REPORTER) \
- --bail \
- test/acceptance/misc/bail
-
-test-async-only:
- @./bin/mocha \
- --reporter $(REPORTER) \
- --async-only \
- test/acceptance/misc/asyncOnly
-
test-glob:
@./test/acceptance/glob/glob.sh
@@ -158,11 +118,10 @@ test-only:
--ui qunit \
test/acceptance/misc/only/qunit
-test-sort:
+test-mocha:
@./bin/mocha \
--reporter $(REPORTER) \
- --sort \
- test/acceptance/sort
+ test/mocha
non-tty:
@./bin/mocha \
@@ -189,4 +148,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 test-failing tm clean
+.PHONY: test-cov test-jsapi test-compilers watch test test-all test-bdd test-tdd test-qunit test-exports test-unit test-integration non-tty tm clean
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..44692d3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+[![Build Status](https://api.travis-ci.org/mochajs/mocha.svg?branch=master)](http://travis-ci.org/mochajs/mocha) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mochajs/mocha?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+ [![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).
+
+## 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)
diff --git a/Readme.md b/Readme.md
deleted file mode 100644
index b84bb05..0000000
--- a/Readme.md
+++ /dev/null
@@ -1,203 +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, 11 months
- active : 433 days
- commits : 1424
- files : 143
- authors :
- 588 TJ Holowaychuk 41.3%
- 389 Tj Holowaychuk 27.3%
- 98 Travis Jeffery 6.9%
- 31 Guillermo Rauch 2.2%
- 13 Attila Domokos 0.9%
- 10 John Firebaugh 0.7%
- 8 Jo Liss 0.6%
- 7 Joshua Appelman 0.5%
- 7 Nathan Rajlich 0.5%
- 6 Brendan Nee 0.4%
- 6 James Carr 0.4%
- 6 Mike Pennisi 0.4%
- 5 Raynos 0.4%
- 5 Aaron Heckmann 0.4%
- 5 Ryunosuke SATO 0.4%
- 4 Forbes Lindesay 0.3%
- 4 Domenic Denicola 0.3%
- 4 Xavier Antoviaque 0.3%
- 4 hokaccha 0.3%
- 4 Jonathan Ong 0.3%
- 4 Joshua Krall 0.3%
- 3 Ben Lindsey 0.2%
- 3 Benjie Gillam 0.2%
- 3 Fredrik Enestad 0.2%
- 3 Sindre Sorhus 0.2%
- 3 Cory Thomas 0.2%
- 3 Mathieu Desvé 0.2%
- 3 Tyson Tate 0.2%
- 3 Valentin Agachi 0.2%
- 3 Wil Moore III 0.2%
- 3 Jesse Dailey 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 FARKAS Máté 0.1%
- 2 Shawn Krisman 0.1%
- 2 Jacob Wejendorp 0.1%
- 2 Jonas Westerlund 0.1%
- 2 Paul Armstrong 0.1%
- 2 Konstantin Käfer 0.1%
- 2 Michael Riley 0.1%
- 2 Michael Schoonmaker 0.1%
- 2 Andreas Lind Petersen 0.1%
- 2 domenic 0.1%
- 2 Quang Van 0.1%
- 2 fcrisci 0.1%
- 2 Nathan Alderson 0.1%
- 2 travis jeffery 0.1%
- 2 Juzer Ali 0.1%
- 2 Pete Hawkins 0.1%
- 2 Justin DuJardin 0.1%
- 2 David Henderson 0.1%
- 2 jsdevel 0.1%
- 2 Timo Tijhof 0.1%
- 2 Brian Beck 0.1%
- 2 Simon Gaeremynck 0.1%
- 2 Ian Storm Taylor 0.1%
- 2 Arian Stolwijk 0.1%
- 2 Alexander Early 0.1%
- 2 Ben Bradley 0.1%
- 2 Glen Mailer 0.1%
- 1 Maciej Małecki 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 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 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 fengmk2 0.1%
- 1 gaye 0.1%
- 1 grasGendarme 0.1%
- 1 lakmeer 0.1%
- 1 lodr 0.1%
- 1 qiuzuhui 0.1%
- 1 sebv 0.1%
- 1 tgautier at 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 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 Casey Foster 0.1%
- 1 ChrisWren 0.1%
- 1 Christopher Hiller 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 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 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 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%
-```
-
-## 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/bin/_mocha b/bin/_mocha
index 3032690..5b3c0c5 100755
--- a/bin/_mocha
+++ b/bin/_mocha
@@ -4,20 +4,17 @@
* Module dependencies.
*/
-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;
+var program = require('commander'),
+ path = require('path'),
+ fs = require('fs'),
+ resolve = path.resolve,
+ exists = fs.existsSync || path.existsSync,
+ Mocha = require('../'),
+ utils = Mocha.utils,
+ join = path.join,
+ cwd = process.cwd(),
+ getOptions = require('./options'),
+ mocha = new Mocha;
/**
* Save timer references to avoid Sinon interfering (see GH-237).
@@ -65,26 +62,34 @@ program
.option('-c, --colors', 'force enabling of colors')
.option('-C, --no-colors', 'force disabling of colors')
.option('-G, --growl', 'enable growl notification support')
+ .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('-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('-f, --fgrep <string>', 'only run tests containing <string>')
+ .option('-gc, --expose-gc', 'expose gc extension')
+ .option('-i, --invert', 'inverts --grep and --fgrep 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('--full-trace', 'display the full stack trace')
.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('--es_staging', 'enable all staged features')
.option('--harmony-collections', 'enable harmony collections (sets, maps, and weak maps)')
.option('--harmony-generators', 'enable harmony generators')
.option('--harmony-proxies', 'enable harmony proxies')
+ .option('--harmony_shipping', 'enable all shipped harmony fetaures (iojs)')
+ .option('--harmony_arrow_functions', 'enable "harmony arrow functions" (iojs)')
+ .option('--harmony_proxies', 'enable "harmony proxies" (iojs)')
+ .option('--harmony_classes', 'enable "harmony classes" (iojs)')
.option('--inline-diffs', 'display actual/expected differences inline within each string')
.option('--interfaces', 'display available interfaces')
.option('--no-deprecation', 'silence deprecation warnings')
@@ -98,6 +103,7 @@ program
.option('--trace', 'trace function calls')
.option('--trace-deprecation', 'show stack traces on deprecations')
.option('--watch-extensions <ext>,...', 'additional extensions to monitor with --watch', list, [])
+ .option('--delay', 'wait for async suite definition')
program.name = 'mocha';
@@ -170,23 +176,9 @@ program.on('require', function(mod){
requires.push(mod);
});
-// --opts
+// load mocha.opts into process.argv
-var optsPath = process.argv.indexOf('--opts') !== -1
- ? process.argv[process.argv.indexOf('--opts') + 1]
- : 'test/mocha.opts';
-
-try {
- var opts = fs.readFileSync(optsPath, 'utf8')
- .trim()
- .split(/\s+/);
-
- process.argv = process.argv
- .slice(0, 2)
- .concat(opts.concat(process.argv.slice(2)));
-} catch (err) {
- // ignore
-}
+getOptions();
// parse args
@@ -196,9 +188,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
@@ -251,6 +256,10 @@ mocha.suite.bail(program.bail);
if (program.grep) mocha.grep(new RegExp(program.grep));
+// --fgrep
+
+if (program.fgrep) mocha.grep(program.fgrep);
+
// --invert
if (program.invert) mocha.invert();
@@ -259,6 +268,10 @@ if (program.invert) mocha.invert();
if (program.checkLeaks) mocha.checkLeaks();
+// --stack-trace
+
+if(program.fullTrace) mocha.fullTrace();
+
// --growl
if (program.growl) mocha.growl();
@@ -267,6 +280,10 @@ if (program.growl) mocha.growl();
if (program.asyncOnly) mocha.asyncOnly();
+// --delay
+
+if (program.delay) mocha.delay();
+
// --globals
mocha.globals(globals);
@@ -282,6 +299,7 @@ program.compilers.forEach(function(c) {
if (mod[0] == '.') mod = join(process.cwd(), mod);
require(mod);
extensions.push(ext);
+ program.watchExtensions.push(ext);
});
// requires
@@ -325,7 +343,7 @@ if (program.watch) {
});
- var watchFiles = utils.files(cwd, [ 'js', 'coffee', 'litcoffee', 'coffee.md' ].concat(program.watchExtensions));
+ var watchFiles = utils.files(cwd, [ 'js' ].concat(program.watchExtensions));
var runAgain = false;
function loadAndRun() {
@@ -377,12 +395,32 @@ if (program.watch) {
// load
mocha.files = files;
-runner = mocha.run(program.exit ? process.exit : exitLater);
+runner = mocha.run(program.exit ? exit : exitLater);
function exitLater(code) {
process.on('exit', function() { process.exit(code) })
}
+function exit(code) {
+ // flush output for Node.js Windows pipe bug
+ // https://github.com/joyent/node/issues/6247 is just one bug example
+ // https://github.com/visionmedia/mocha/issues/333 has a good discussion
+ function done() {
+ if (!(draining--)) process.exit(code);
+ }
+
+ var draining = 0;
+ var streams = [process.stdout, process.stderr];
+
+ streams.forEach(function(stream){
+ // submit empty write request and wait for completion
+ draining += 1;
+ stream.write('', done);
+ });
+
+ done();
+}
+
process.on('SIGINT', function() { runner.abort(); })
// enable growl notifications
@@ -419,7 +457,7 @@ function list(str) {
function hideCursor(){
process.stdout.write('\u001b[?25l');
-};
+}
/**
* Show the cursor.
@@ -427,7 +465,7 @@ function hideCursor(){
function showCursor(){
process.stdout.write('\u001b[?25h');
-};
+}
/**
* Stop play()ing.
diff --git a/bin/mocha b/bin/mocha
index b5dbc72..daa8fd9 100755
--- a/bin/mocha
+++ b/bin/mocha
@@ -5,8 +5,15 @@
* when found, before invoking the "real" _mocha(1) executable.
*/
-var spawn = require('child_process').spawn
- , args = [ __dirname + '/_mocha' ];
+var spawn = require('child_process').spawn,
+ path = require('path'),
+ fs = require('fs'),
+ args = [path.join(__dirname, '_mocha')],
+ getOptions = require('./options');
+
+// load mocha.opts into process.argv
+
+getOptions();
process.argv.slice(2).forEach(function(arg){
var flag = arg.split('=')[0];
@@ -28,13 +35,19 @@ process.argv.slice(2).forEach(function(arg){
break;
case '--gc-global':
case '--harmony':
+ case '--es_staging':
case '--harmony-proxies':
case '--harmony-collections':
case '--harmony-generators':
+ case '--harmony_shipping':
+ case '--harmony_arrow_functions':
+ case '--harmony_proxies':
+ case '--harmony_classes':
case '--no-deprecation':
case '--prof':
case '--throw-deprecation':
case '--trace-deprecation':
+ case '--allow-natives-syntax':
args.unshift(arg);
break;
default:
@@ -44,7 +57,7 @@ process.argv.slice(2).forEach(function(arg){
}
});
-var proc = spawn(process.argv[0], args, { customFds: [0,1,2] });
+var proc = spawn(process.execPath, args, { stdio: 'inherit' });
proc.on('exit', function (code, signal) {
process.on('exit', function(){
if (signal) {
@@ -54,3 +67,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/bin/options.js b/bin/options.js
new file mode 100644
index 0000000..3b31798
--- /dev/null
+++ b/bin/options.js
@@ -0,0 +1,36 @@
+/**
+ * Dependencies.
+ */
+
+var fs = require('fs');
+
+/**
+ * Export `getOptions`.
+ */
+
+module.exports = getOptions;
+
+/**
+ * Get options.
+ */
+
+function getOptions() {
+ var optsPath = process.argv.indexOf('--opts') !== -1
+ ? process.argv[process.argv.indexOf('--opts') + 1]
+ : 'test/mocha.opts';
+
+ try {
+ var opts = fs.readFileSync(optsPath, 'utf8')
+ .trim()
+ .split(/\s+/)
+ .filter(function(value) {
+ return value ? true : false;
+ });
+
+ process.argv = process.argv
+ .slice(0, 2)
+ .concat(opts.concat(process.argv.slice(2)));
+ } catch (err) {
+ // ignore
+ }
+}
diff --git a/bower.json b/bower.json
index 839191b..f03b076 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,22 @@
{
"name": "mocha",
- "version": "1.21.5",
+ "version": "2.2.5",
+ "homepage": "http://mocha.github.io/mocha",
+ "description": "simple, flexible, fun test framework",
+ "authors": [
+ "TJ Holowaychuk <tj at vision-media.ca>",
+ "Joshua Appelman <joshua at jbna.nl>",
+ "Oleg Gaidarenko <markelog at gmail.com>",
+ "Christoffer Hallas <christoffer.hallas at gmail.com>",
+ "Christopher Hiller <chiller at badwing.com>",
+ "Travis Jeffery <tj at travisjeffery.com>",
+ "Johnathan Ong <me at jongleberry.com>",
+ "Guillermo Rauch <rauchg at gmail.com>"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/mochajs/mocha.git"
+ },
"main": [
"mocha.js",
"mocha.css"
@@ -19,5 +35,13 @@
"index.js",
"Makefile",
"package.json"
- ]
-}
+ ],
+ "keywords": [
+ "mocha",
+ "test",
+ "bdd",
+ "tdd",
+ "tap"
+ ],
+ "license": "MIT"
+}
\ No newline at end of file
diff --git a/component.json b/component.json
index eb7cdb8..5da3daa 100644
--- a/component.json
+++ b/component.json
@@ -1,7 +1,7 @@
{
"name": "mocha",
- "version": "1.21.5",
- "repo": "visionmedia/mocha",
+ "version": "2.2.5",
+ "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/index.js b/index.js
index 507566f..169b271 100644
--- a/index.js
+++ b/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/lib/browser/debug.js b/lib/browser/debug.js
index 03cf592..0d939e5 100644
--- a/lib/browser/debug.js
+++ b/lib/browser/debug.js
@@ -1,4 +1,3 @@
-
module.exports = function(type){
return function(){
}
diff --git a/lib/browser/escape-string-regexp.js b/lib/browser/escape-string-regexp.js
index ac6572c..21a9566 100644
--- a/lib/browser/escape-string-regexp.js
+++ b/lib/browser/escape-string-regexp.js
@@ -3,9 +3,9 @@
var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
module.exports = function (str) {
- if (typeof str !== 'string') {
- throw new TypeError('Expected a string');
- }
+ if (typeof str !== 'string') {
+ throw new TypeError('Expected a string');
+ }
- return str.replace(matchOperatorsRe, '\\$&');
+ return str.replace(matchOperatorsRe, '\\$&');
};
diff --git a/lib/browser/events.js b/lib/browser/events.js
index cfbd072..f708260 100644
--- a/lib/browser/events.js
+++ b/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/lib/browser/progress.js b/lib/browser/progress.js
index 90526f7..b30e517 100644
--- a/lib/browser/progress.js
+++ b/lib/browser/progress.js
@@ -94,28 +94,28 @@ Progress.prototype.draw = function(ctx){
, y = half
, rad = half - 1
, fontSize = this._fontSize;
-
+
ctx.font = fontSize + 'px ' + this._font;
-
+
var angle = Math.PI * 2 * (percent / 100);
ctx.clearRect(0, 0, size, size);
-
+
// outer circle
ctx.strokeStyle = '#9f9f9f';
ctx.beginPath();
ctx.arc(x, y, rad, 0, angle, false);
ctx.stroke();
-
+
// inner circle
ctx.strokeStyle = '#eee';
ctx.beginPath();
ctx.arc(x, y, rad - 1, 0, angle, true);
ctx.stroke();
-
+
// text
var text = this._text || (percent | 0) + '%'
, w = ctx.measureText(text).width;
-
+
ctx.fillText(
text
, x - w / 2 + 1
diff --git a/lib/browser/tty.js b/lib/browser/tty.js
index 6f5f079..eab6388 100644
--- a/lib/browser/tty.js
+++ b/lib/browser/tty.js
@@ -1,4 +1,3 @@
-
exports.isatty = function(){
return true;
};
diff --git a/lib/context.js b/lib/context.js
index 84440be..3885218 100644
--- a/lib/context.js
+++ b/lib/context.js
@@ -1,4 +1,3 @@
-
/**
* Expose `Context`.
*/
@@ -69,6 +68,18 @@ Context.prototype.slow = function(ms){
};
/**
+ * Mark a test as skipped.
+ *
+ * @return {Context} self
+ * @api private
+ */
+
+Context.prototype.skip = function(){
+ this.runnable().skip();
+ return this;
+};
+
+/**
* Inspect the context void of `._runnable`.
*
* @return {String}
diff --git a/lib/hook.js b/lib/hook.js
index 814e7b6..c2dc346 100644
--- a/lib/hook.js
+++ b/lib/hook.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/lib/interfaces/bdd.js b/lib/interfaces/bdd.js
index ac16d72..f9f08a3 100644
--- a/lib/interfaces/bdd.js
+++ b/lib/interfaces/bdd.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
@@ -30,38 +29,13 @@ module.exports = function(suite){
suite.on('pre-require', function(context, file, mocha){
- /**
- * Execute before running tests.
- */
-
- context.before = function(name, fn){
- suites[0].beforeAll(name, fn);
- };
-
- /**
- * Execute after running tests.
- */
-
- context.after = function(name, fn){
- suites[0].afterAll(name, fn);
- };
-
- /**
- * Execute before each test case.
- */
-
- context.beforeEach = function(name, fn){
- suites[0].beforeEach(name, fn);
- };
-
- /**
- * Execute after each test case.
- */
-
- context.afterEach = function(name, fn){
- suites[0].afterEach(name, fn);
- };
+ var common = require('./common')(suites, context);
+ context.before = common.before;
+ context.after = common.after;
+ context.beforeEach = common.beforeEach;
+ context.afterEach = common.afterEach;
+ context.run = mocha.options.delay && common.runWithSuite(suite);
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
@@ -136,5 +110,6 @@ module.exports = function(suite){
context.it.skip = function(title){
context.it(title);
};
+
});
};
diff --git a/lib/interfaces/common.js b/lib/interfaces/common.js
new file mode 100644
index 0000000..1ccd339
--- /dev/null
+++ b/lib/interfaces/common.js
@@ -0,0 +1,58 @@
+/**
+ * Functions common to more than one interface
+ * @module lib/interfaces/common
+ */
+
+'use strict';
+
+module.exports = function (suites, context) {
+
+ return {
+ /**
+ * This is only present if flag --delay is passed into Mocha. It triggers
+ * root suite execution. Returns a function which runs the root suite.
+ */
+ runWithSuite: function runWithSuite(suite) {
+ return function run() {
+ suite.run();
+ };
+ },
+
+ /**
+ * Execute before running tests.
+ */
+ before: function (name, fn) {
+ suites[0].beforeAll(name, fn);
+ },
+
+ /**
+ * Execute after running tests.
+ */
+ after: function (name, fn) {
+ suites[0].afterAll(name, fn);
+ },
+
+ /**
+ * Execute before each test case.
+ */
+ beforeEach: function (name, fn) {
+ suites[0].beforeEach(name, fn);
+ },
+
+ /**
+ * Execute after each test case.
+ */
+ afterEach: function (name, fn) {
+ suites[0].afterEach(name, fn);
+ },
+
+ test: {
+ /**
+ * Pending test case.
+ */
+ skip: function (title) {
+ context.test(title);
+ }
+ }
+ }
+};
diff --git a/lib/interfaces/exports.js b/lib/interfaces/exports.js
index cedb905..95e8a07 100644
--- a/lib/interfaces/exports.js
+++ b/lib/interfaces/exports.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/lib/interfaces/index.js b/lib/interfaces/index.js
index f7b2655..4f825d1 100644
--- a/lib/interfaces/index.js
+++ b/lib/interfaces/index.js
@@ -1,4 +1,3 @@
-
exports.bdd = require('./bdd');
exports.tdd = require('./tdd');
exports.qunit = require('./qunit');
diff --git a/lib/interfaces/qunit.js b/lib/interfaces/qunit.js
index 0a22641..6668967 100644
--- a/lib/interfaces/qunit.js
+++ b/lib/interfaces/qunit.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
@@ -38,38 +37,13 @@ module.exports = function(suite){
suite.on('pre-require', function(context, file, mocha){
- /**
- * Execute before running tests.
- */
-
- context.before = function(name, fn){
- suites[0].beforeAll(name, fn);
- };
-
- /**
- * Execute after running tests.
- */
-
- context.after = function(name, fn){
- suites[0].afterAll(name, fn);
- };
-
- /**
- * Execute before each test case.
- */
-
- context.beforeEach = function(name, fn){
- suites[0].beforeEach(name, fn);
- };
-
- /**
- * Execute after each test case.
- */
-
- context.afterEach = function(name, fn){
- suites[0].afterEach(name, fn);
- };
+ var common = require('./common')(suites, context);
+ context.before = common.before;
+ context.after = common.after;
+ context.beforeEach = common.beforeEach;
+ context.afterEach = common.afterEach;
+ context.run = mocha.options.delay && common.runWithSuite(suite);
/**
* Describe a "suite" with the given `title`.
*/
@@ -114,12 +88,7 @@ module.exports = function(suite){
mocha.grep(new RegExp(reString));
};
- /**
- * Pending test case.
- */
+ context.test.skip = common.test.skip;
- context.test.skip = function(title){
- context.test(title);
- };
});
};
diff --git a/lib/interfaces/tdd.js b/lib/interfaces/tdd.js
index dc43e41..13bc2a3 100644
--- a/lib/interfaces/tdd.js
+++ b/lib/interfaces/tdd.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
@@ -38,38 +37,13 @@ module.exports = function(suite){
suite.on('pre-require', function(context, file, mocha){
- /**
- * Execute before each test case.
- */
-
- context.setup = function(name, fn){
- suites[0].beforeEach(name, fn);
- };
-
- /**
- * Execute after each test case.
- */
-
- context.teardown = function(name, fn){
- suites[0].afterEach(name, fn);
- };
-
- /**
- * Execute before the suite.
- */
-
- context.suiteSetup = function(name, fn){
- suites[0].beforeAll(name, fn);
- };
-
- /**
- * Execute after the suite.
- */
-
- context.suiteTeardown = function(name, fn){
- suites[0].afterAll(name, fn);
- };
+ var common = require('./common')(suites, context);
+ context.setup = common.beforeEach;
+ context.teardown = common.afterEach;
+ context.suiteSetup = common.before;
+ context.suiteTeardown = common.after;
+ context.run = mocha.options.delay && common.runWithSuite(suite);
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
@@ -130,12 +104,6 @@ module.exports = function(suite){
mocha.grep(new RegExp(reString));
};
- /**
- * Pending test case.
- */
-
- context.test.skip = function(title){
- context.test(title);
- };
+ context.test.skip = common.test.skip;
});
};
diff --git a/lib/mocha.js b/lib/mocha.js
index 73bdaf9..8a11124 100644
--- a/lib/mocha.js
+++ b/lib/mocha.js
@@ -66,6 +66,7 @@ function image(name) {
* - `bail` bail on the first test failure
* - `slow` milliseconds to wait before considering a test slow
* - `ignoreLeaks` ignore global leaks
+ * - `fullTrace` display the full stack-trace on failing
* - `grep` string or regexp to filter tests with
*
* @param {Object} options
@@ -76,13 +77,14 @@ function Mocha(options) {
options = options || {};
this.files = [];
this.options = options;
- this.grep(options.grep);
+ if (options.grep) this.grep(new RegExp(options.grep));
+ if (options.fgrep) this.grep(options.fgrep);
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)
+ this.useColors(options.useColors);
if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts);
if (options.slow) this.slow(options.slow);
@@ -99,6 +101,7 @@ function Mocha(options) {
exports.suite = context.suite || context.describe;
exports.teardown = context.teardown || context.afterEach;
exports.test = context.test || context.it;
+ exports.run = context.run;
});
}
@@ -131,17 +134,21 @@ Mocha.prototype.addFile = function(file){
* 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 || 'spec';
var _reporter;
- try { _reporter = require('./reporters/' + reporter); } catch (err) {};
- if (!_reporter) try { _reporter = require(reporter); } catch (err) {};
+ try { _reporter = require('./reporters/' + reporter); } catch (err) {}
+ if (!_reporter) try { _reporter = require(reporter); } catch (err) {
+ err.message.indexOf('Cannot find module') !== -1
+ ? console.warn('"' + reporter + '" reporter not found')
+ : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack);
+ }
if (!_reporter && reporter === 'teamcity')
console.warn('The Teamcity reporter was moved to a package named ' +
'mocha-teamcity-reporter ' +
@@ -149,6 +156,7 @@ Mocha.prototype.reporter = function(reporter){
if (!_reporter) throw new Error('invalid reporter "' + reporter + '"');
this._reporter = _reporter;
}
+ this.options.reporterOptions = reporterOptions;
return this;
};
@@ -162,7 +170,7 @@ Mocha.prototype.reporter = function(reporter){
Mocha.prototype.ui = function(name){
name = name || 'bdd';
this._ui = exports.interfaces[name];
- if (!this._ui) try { this._ui = require(name); } catch (err) {};
+ if (!this._ui) try { this._ui = require(name); } catch (err) {}
if (!this._ui) throw new Error('invalid interface "' + name + '"');
this._ui = this._ui(this.suite);
return this;
@@ -264,6 +272,18 @@ Mocha.prototype.checkLeaks = function(){
};
/**
+ * Display long stack-trace on failing
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.fullTrace = function() {
+ this.options.fullStackTrace = true;
+ return this;
+};
+
+/**
* Enable growl support.
*
* @return {Mocha}
@@ -297,9 +317,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;
};
@@ -382,26 +402,45 @@ Mocha.prototype.noHighlighting = function() {
};
/**
+ * Delay root suite execution.
+ * @returns {Mocha}
+ * @api public
+ */
+Mocha.prototype.delay = function delay() {
+ this.options.delay = true;
+ return this;
+};
+
+/**
* Run tests and invoke `fn()` when complete.
*
* @param {Function} fn
* @return {Runner}
* @api public
*/
-
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 runner = new exports.Runner(suite, options.delay);
var reporter = new this._reporter(runner, options);
runner.ignoreLeaks = false !== options.ignoreLeaks;
+ runner.fullStackTrace = options.fullStackTrace;
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 && fn(failures);
+ }
+
+ return runner.run(done);
};
diff --git a/lib/pending.js b/lib/pending.js
new file mode 100644
index 0000000..265ec73
--- /dev/null
+++ b/lib/pending.js
@@ -0,0 +1,16 @@
+
+/**
+ * Expose `Pending`.
+ */
+
+module.exports = Pending;
+
+/**
+ * Initialize a new `Pending` error with the given message.
+ *
+ * @param {String} message
+ */
+
+function Pending(message) {
+ this.message = message;
+}
diff --git a/lib/reporters/base.js b/lib/reporters/base.js
index 00c94de..9b719a8 100644
--- a/lib/reporters/base.js
+++ b/lib/reporters/base.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
@@ -6,7 +5,8 @@
var tty = require('tty')
, diff = require('diff')
, ms = require('../ms')
- , utils = require('../utils');
+ , utils = require('../utils')
+ , supportsColor = process.env ? require('supports-color') : null;
/**
* Save timer references to avoid Sinon interfering (see GH-237).
@@ -31,10 +31,12 @@ var isatty = tty.isatty(1) && tty.isatty(2);
exports = module.exports = Base;
/**
- * Enable coloring by default.
+ * Enable coloring by default, except in the browser interface.
*/
-exports.useColors = isatty || (process.env.MOCHA_COLORS !== undefined);
+exports.useColors = process.env
+ ? (supportsColor || (process.env.MOCHA_COLORS !== undefined))
+ : false;
/**
* Inline diffs instead of +/-
@@ -64,8 +66,8 @@ exports.colors = {
, 'green': 32
, 'light': 90
, 'diff gutter': 90
- , 'diff added': 42
- , 'diff removed': 41
+ , 'diff added': 32
+ , 'diff removed': 31
};
/**
@@ -98,7 +100,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 +157,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')
@@ -166,26 +168,33 @@ exports.list = function(failures){
var err = test.err
, message = err.message || ''
, stack = err.stack || message
- , index = stack.indexOf(message) + message.length
- , msg = stack.slice(0, index)
+ , index = stack.indexOf(message)
, actual = err.actual
, expected = err.expected
, escape = true;
+ if (index === -1) {
+ msg = message;
+ } else {
+ index += message.length;
+ msg = stack.slice(0, index);
+ // remove msg from stack
+ stack = stack.slice(index + 1);
+ }
// uncaught
if (err.uncaught) {
msg = 'Uncaught ' + msg;
}
-
// explicitly show diff
- if (err.showDiff && sameType(actual, expected)) {
+ if (err.showDiff !== false && sameType(actual, expected)
+ && expected !== undefined) {
+
escape = false;
- err.actual = actual = utils.stringify(actual);
- err.expected = expected = utils.stringify(expected);
- }
+ if (!(utils.isString(actual) && utils.isString(expected))) {
+ err.actual = actual = utils.stringify(actual);
+ err.expected = expected = utils.stringify(expected);
+ }
- // actual / expected diff
- if (err.showDiff && 'string' == typeof actual && 'string' == typeof expected) {
fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
var match = message.match(/^([^:]+): expected/);
msg = '\n ' + color('error message', match ? match[1] : msg);
@@ -197,11 +206,10 @@ exports.list = function(failures){
}
}
- // indent stack trace without msg
- stack = stack.slice(index ? index + 1 : index)
- .replace(/^/gm, ' ');
+ // indent stack trace
+ stack = stack.replace(/^/gm, ' ');
- console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
+ console.log(fmt, (i + 1), test.fullTitle(), msg, stack);
});
};
@@ -306,11 +314,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();
@@ -388,7 +395,7 @@ function unifiedDiff(err, escape) {
function notBlank(line) {
return line != null;
}
- msg = diff.createPatch('string', err.actual, err.expected);
+ var msg = diff.createPatch('string', err.actual, err.expected);
var lines = msg.split('\n').splice(4);
return '\n '
+ colorLines('diff added', '+ expected') + ' '
diff --git a/lib/reporters/doc.js b/lib/reporters/doc.js
index eab72e5..d194eb0 100644
--- a/lib/reporters/doc.js
+++ b/lib/reporters/doc.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/lib/reporters/dot.js b/lib/reporters/dot.js
index e200468..42a45ee 100644
--- a/lib/reporters/dot.js
+++ b/lib/reporters/dot.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
@@ -28,7 +27,7 @@ function Dot(runner) {
, n = -1;
runner.on('start', function(){
- process.stdout.write('\n ');
+ process.stdout.write('\n');
});
runner.on('pending', function(test){
diff --git a/lib/reporters/html-cov.js b/lib/reporters/html-cov.js
index bfb27ff..74b46ad 100644
--- a/lib/reporters/html-cov.js
+++ b/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/lib/reporters/html.js b/lib/reporters/html.js
index 8b44e3e..aec2af0 100644
--- a/lib/reporters/html.js
+++ b/lib/reporters/html.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
@@ -136,7 +135,7 @@ function HTML(runner) {
} 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,13 +177,28 @@ function HTML(runner) {
}
/**
+ * 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;
+
+ // Remove previous grep query parameter if present
+ if (search) {
+ search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?');
+ }
+
+ 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());
};
/**
@@ -194,7 +208,7 @@ HTML.prototype.suiteURL = function(suite){
*/
HTML.prototype.testURL = function(test){
- return '?grep=' + encodeURIComponent(test.fullTitle());
+ return makeUrl(test.fullTitle());
};
/**
diff --git a/lib/reporters/index.js b/lib/reporters/index.js
index 1c4fccf..87b76d9 100644
--- a/lib/reporters/index.js
+++ b/lib/reporters/index.js
@@ -1,4 +1,3 @@
-
exports.Base = require('./base');
exports.Dot = require('./dot');
exports.Doc = require('./doc');
diff --git a/lib/reporters/json-cov.js b/lib/reporters/json-cov.js
index 83e57f4..309c0ef 100644
--- a/lib/reporters/json-cov.js
+++ b/lib/reporters/json-cov.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/lib/reporters/json-stream.js b/lib/reporters/json-stream.js
index 7cb8fbe..f7c05a8 100644
--- a/lib/reporters/json-stream.js
+++ b/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/lib/reporters/json.js b/lib/reporters/json.js
index 4ec9e12..f565506 100644
--- a/lib/reporters/json.js
+++ b/lib/reporters/json.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/lib/reporters/landing.js b/lib/reporters/landing.js
index bf064f6..ee004a2 100644
--- a/lib/reporters/landing.js
+++ b/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/lib/reporters/list.js b/lib/reporters/list.js
index 3328e15..f64367a 100644
--- a/lib/reporters/list.js
+++ b/lib/reporters/list.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/lib/reporters/markdown.js b/lib/reporters/markdown.js
index 6383a64..e14174c 100644
--- a/lib/reporters/markdown.js
+++ b/lib/reporters/markdown.js
@@ -6,6 +6,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/lib/reporters/min.js b/lib/reporters/min.js
index 1b6117d..ce1a3fe 100644
--- a/lib/reporters/min.js
+++ b/lib/reporters/min.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/lib/reporters/nyan.js b/lib/reporters/nyan.js
index a8d43bf..63056b1 100644
--- a/lib/reporters/nyan.js
+++ b/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');
@@ -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/lib/reporters/spec.js b/lib/reporters/spec.js
index ada25c3..3debffe 100644
--- a/lib/reporters/spec.js
+++ b/lib/reporters/spec.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
@@ -55,14 +54,14 @@ function Spec(runner) {
if ('fast' == test.speed) {
var fmt = indent()
+ color('checkmark', ' ' + Base.symbols.ok)
- + color('pass', ' %s ');
+ + color('pass', ' %s');
cursor.CR();
console.log(fmt, test.title);
} else {
var fmt = indent()
+ color('checkmark', ' ' + Base.symbols.ok)
- + color('pass', ' %s ')
- + color(test.speed, '(%dms)');
+ + color('pass', ' %s')
+ + color(test.speed, ' (%dms)');
cursor.CR();
console.log(fmt, test.title, test.duration);
}
diff --git a/lib/reporters/tap.js b/lib/reporters/tap.js
index 2bcd995..01a92eb 100644
--- a/lib/reporters/tap.js
+++ b/lib/reporters/tap.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/lib/reporters/templates/menu.jade b/lib/reporters/templates/menu.jade
index e9ba464..c682e3f 100644
--- a/lib/reporters/templates/menu.jade
+++ b/lib/reporters/templates/menu.jade
@@ -10,4 +10,4 @@
if segments.length
span.dirname= segments.join('/') + '/'
span.basename= basename
- a#logo(href='http://visionmedia.github.io/mocha/') m
+ a#logo(href='http://mochajs.org/') m
diff --git a/lib/reporters/templates/style.html b/lib/reporters/templates/style.html
index 643c0ab..4c9c37c 100644
--- a/lib/reporters/templates/style.html
+++ b/lib/reporters/templates/style.html
@@ -8,7 +8,7 @@ body {
}
#coverage {
- padding: 60px;
+ padding: 60px 400px 60px 60px;
}
h1 a {
@@ -124,6 +124,10 @@ footer span {
padding: 15px 0;
text-align: right;
border-left: 1px solid #eee;
+ max-width: 400px;
+ overflow: auto;
+ white-space: nowrap;
+
-moz-box-shadow: 0 0 2px #888
, inset 5px 0 20px rgba(0,0,0,.5)
, inset 5px 0 3px rgba(0,0,0,.3);
@@ -317,4 +321,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/lib/reporters/xunit.js b/lib/reporters/xunit.js
index 3506a07..77cd347 100644
--- a/lib/reporters/xunit.js
+++ b/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,13 +114,13 @@ function test(test) {
if ('failed' == test.state) {
var err = test.err;
- console.log(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + 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/lib/runnable.js b/lib/runnable.js
index 9409007..6e4803f 100644
--- a/lib/runnable.js
+++ b/lib/runnable.js
@@ -1,11 +1,12 @@
-
/**
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter
, debug = require('debug')('mocha:runnable')
- , milliseconds = require('./ms');
+ , Pending = require('./pending')
+ , milliseconds = require('./ms')
+ , utils = require('./utils');
/**
* Save timer references to avoid Sinon interfering (see GH-237).
@@ -46,6 +47,7 @@ function Runnable(title, fn) {
this._slow = 75;
this._enableTimeouts = true;
this.timedOut = false;
+ this._trace = new Error('done() called multiple times')
}
/**
@@ -104,6 +106,16 @@ Runnable.prototype.enableTimeouts = function(enabled){
};
/**
+ * Halt and mark as pending.
+ *
+ * @api private
+ */
+
+Runnable.prototype.skip = function(){
+ throw new Pending();
+};
+
+/**
* Return the full title generated by recursively
* concatenating the parent's full title.
*
@@ -155,7 +167,7 @@ Runnable.prototype.resetTimeout = function(){
this.clearTimeout();
this.timer = setTimeout(function(){
if (!self._enableTimeouts) return;
- self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
+ self.callback(new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'));
self.timedOut = true;
}, ms);
};
@@ -191,18 +203,22 @@ Runnable.prototype.run = function(fn){
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);
+
+ // Discard the resolution if this test has already failed asynchronously
+ if (self.state) return;
+
self.clearTimeout();
self.duration = new Date - start;
finished = true;
- if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded');
+ if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.');
fn(err);
}
@@ -226,7 +242,7 @@ Runnable.prototype.run = function(fn){
done();
});
} catch (err) {
- done(err);
+ done(utils.getError(err));
}
return;
}
@@ -243,7 +259,7 @@ Runnable.prototype.run = function(fn){
callFn(this.fn);
}
} catch (err) {
- done(err);
+ done(utils.getError(err));
}
function callFn(fn) {
diff --git a/lib/runner.js b/lib/runner.js
index b5a6d49..3199dc9 100644
--- a/lib/runner.js
+++ b/lib/runner.js
@@ -4,10 +4,14 @@
var EventEmitter = require('events').EventEmitter
, debug = require('debug')('mocha:runner')
+ , Pending = require('./pending')
, Test = require('./test')
, utils = require('./utils')
, filter = utils.filter
- , keys = utils.keys;
+ , keys = utils.keys
+ , type = utils.type
+ , stringify = utils.stringify
+ , stackFilter = utils.stackTraceFilter();
/**
* Non-enumerable globals.
@@ -19,7 +23,9 @@ var globals = [
'setInterval',
'clearInterval',
'XMLHttpRequest',
- 'Date'
+ 'Date',
+ 'setImmediate',
+ 'clearImmediate'
];
/**
@@ -45,13 +51,17 @@ module.exports = Runner;
* - `fail` (test, err) test failed
* - `pending` (test) test pending
*
+ * @param {Suite} suite Root suite
+ * @param {boolean} [delay] Whether or not to delay execution of root suite
+ * until ready.
* @api public
*/
-function Runner(suite) {
+function Runner(suite, delay) {
var self = this;
this._globals = [];
this._abort = false;
+ this._delay = delay;
this.suite = suite;
this.total = suite.total();
this.failures = 0;
@@ -188,14 +198,18 @@ Runner.prototype.checkGlobals = function(test){
* @api private
*/
-Runner.prototype.fail = function(test, err){
+Runner.prototype.fail = function(test, err) {
++this.failures;
test.state = 'failed';
- if ('string' == typeof err) {
- err = new Error('the string "' + err + '" was thrown, throw an Error :)');
+ if (!(err instanceof Error)) {
+ err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)');
}
+ err.stack = (this.fullStackTrace || !err.stack)
+ ? err.stack
+ : stackFilter(err.stack);
+
this.emit('fail', test, err);
};
@@ -244,7 +258,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;
@@ -260,10 +273,14 @@ Runner.prototype.hook = function(name, fn){
var testError = hook.error();
if (testError) self.fail(self.test, testError);
if (err) {
- self.failHook(hook, err);
+ if (err instanceof Pending) {
+ suite.pending = true;
+ } else {
+ self.failHook(hook, err);
- // stop executing hooks, notify callee of hook err
- return fn(err);
+ // stop executing hooks, notify callee of hook err
+ return fn(err);
+ }
}
self.emit('hook end', hook);
delete hook.ctx.currentTest;
@@ -445,6 +462,11 @@ Runner.prototype.runTests = function(suite, fn){
self.emit('test', self.test = test);
self.hookDown('beforeEach', function(err, errSuite){
+ if (suite.pending) {
+ self.emit('pending', test);
+ self.emit('test end', test);
+ return next();
+ }
if (err) return hookErr(err, errSuite, false);
self.currentRunnable = self.test;
@@ -452,8 +474,17 @@ Runner.prototype.runTests = function(suite, fn){
test = self.test;
if (err) {
- self.fail(test, err);
+ if (err instanceof Pending) {
+ self.emit('pending', test);
+ } else {
+ self.fail(test, err);
+ }
self.emit('test end', test);
+
+ if (err instanceof Pending) {
+ return next();
+ }
+
return self.hookUp('afterEach', next);
}
@@ -538,19 +569,18 @@ Runner.prototype.uncaught = function(err){
}.call(err) ? err : ( err.message || err ));
} else {
debug('uncaught undefined exception');
- err = new Error('Caught undefined error, did you throw without specifying what?');
+ 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;
+ // Ignore errors if complete
+ if (runnable.state) return;
+ this.fail(runnable, err);
// recover from test
if ('test' == runnable.type) {
@@ -573,13 +603,23 @@ Runner.prototype.uncaught = function(err){
*/
Runner.prototype.run = function(fn){
- var self = this
- , fn = fn || function(){};
+ var self = this,
+ rootSuite = this.suite;
+
+ fn = fn || function(){};
function uncaught(err){
self.uncaught(err);
}
+ function start() {
+ self.emit('start');
+ self.runSuite(rootSuite, function(){
+ debug('finished running');
+ self.emit('end');
+ });
+ }
+
debug('start');
// callback
@@ -589,16 +629,19 @@ Runner.prototype.run = function(fn){
fn(self.failures);
});
- // run suites
- this.emit('start');
- this.runSuite(this.suite, function(){
- debug('finished running');
- self.emit('end');
- });
-
// uncaught exception
process.on('uncaughtException', uncaught);
+ if (this._delay) {
+ // for reporters, I guess.
+ // might be nice to debounce some dots while we wait.
+ this.emit('waiting', rootSuite);
+ rootSuite.once('run', start);
+ }
+ else {
+ start();
+ }
+
return this;
};
@@ -654,20 +697,20 @@ function filterLeaks(ok, globals) {
* @api private
*/
- function extraGlobals() {
- if (typeof(process) === 'object' &&
- typeof(process.version) === 'string') {
+function extraGlobals() {
+ if (typeof(process) === 'object' &&
+ typeof(process.version) === 'string') {
- var nodeVersion = process.version.split('.').reduce(function(a, v) {
- return a << 8 | v;
- });
-
- // 'errno' was renamed to process._errno in v0.9.11.
+ var nodeVersion = process.version.split('.').reduce(function(a, v) {
+ return a << 8 | v;
+ });
- if (nodeVersion < 0x00090B) {
- return ['errno'];
- }
- }
+ // 'errno' was renamed to process._errno in v0.9.11.
- return [];
+ if (nodeVersion < 0x00090B) {
+ return ['errno'];
+ }
}
+
+ return [];
+}
diff --git a/lib/suite.js b/lib/suite.js
index e8696f4..edc820e 100644
--- a/lib/suite.js
+++ b/lib/suite.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
@@ -63,6 +62,7 @@ function Suite(title, parentContext) {
this._enableTimeouts = true;
this._slow = 75;
this._bail = false;
+ this.delayed = false;
}
/**
@@ -99,7 +99,7 @@ Suite.prototype.clone = function(){
Suite.prototype.timeout = function(ms){
if (0 == arguments.length) return this._timeout;
- if (ms === 0) this._enableTimeouts = false;
+ if (ms.toString() === '0') this._enableTimeouts = false;
if ('string' == typeof ms) ms = milliseconds(ms);
debug('timeout %d', ms);
this._timeout = parseInt(ms, 10);
@@ -140,7 +140,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
*/
@@ -344,3 +344,12 @@ Suite.prototype.eachTest = function(fn){
});
return this;
};
+
+/**
+ * This will run the root suite if we happen to be running in delayed mode.
+ */
+Suite.prototype.run = function run() {
+ if (this.root) {
+ this.emit('run');
+ }
+};
diff --git a/lib/test.js b/lib/test.js
index 11773e0..4a4cf63 100644
--- a/lib/test.js
+++ b/lib/test.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/lib/utils.js b/lib/utils.js
index ecc0a14..845f84c 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -47,6 +47,17 @@ exports.forEach = function(arr, fn, scope){
};
/**
+ * Test if the given obj is type of string
+ *
+ * @param {Object} obj
+ * @returns Boolean
+ */
+
+exports.isString = function(obj) {
+ return 'string' === typeof obj;
+};
+
+/**
* Array#map (<=IE8)
*
* @param {Array} array
@@ -58,7 +69,7 @@ exports.forEach = function(arr, fn, scope){
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));
+ result.push(fn.call(scope, arr[i], i, arr));
return result;
};
@@ -127,7 +138,7 @@ exports.filter = function(arr, fn){
exports.keys = Object.keys || function(obj) {
var keys = []
- , has = Object.prototype.hasOwnProperty // for `window` on <=IE8
+ , has = Object.prototype.hasOwnProperty; // for `window` on <=IE8
for (var key in obj) {
if (has.call(obj, key)) {
@@ -158,6 +169,28 @@ exports.watch = function(files, fn){
};
/**
+ * Array.isArray (<=IE8)
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+var isArray = Array.isArray || function (obj) {
+ return '[object Array]' == {}.toString.call(obj);
+};
+
+/**
+ * @description
+ * Buffer.prototype.toJSON polyfill
+ * @type {Function}
+ */
+if(typeof Buffer !== 'undefined' && Buffer.prototype) {
+ Buffer.prototype.toJSON = Buffer.prototype.toJSON || function () {
+ return Array.prototype.slice.call(this, 0);
+ };
+}
+
+/**
* Ignored files.
*/
@@ -179,15 +212,15 @@ exports.files = function(dir, ext, ret){
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);
- }
- });
+ .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;
};
@@ -215,7 +248,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 *\(.*\)\s*{|\(.*\) *=> *{?/, '')
.replace(/\s+\}$/, '');
var spaces = str.match(/^\n?( *)/)[1].length
@@ -292,54 +325,256 @@ exports.highlightTags = function(name) {
}
};
+/**
+ * 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();
+};
/**
- * Stringify `obj`.
+ * @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().
*
- * @param {Object} obj
- * @return {String}
+ * @see exports.type
+ * @param {*} value
+ * @return {string}
* @api private
*/
-exports.stringify = function(obj) {
- if (obj instanceof RegExp) return obj.toString();
- return JSON.stringify(exports.canonicalize(obj), null, 2).replace(/,(\n|$)/g, '$1');
+exports.stringify = function(value) {
+ var type = exports.type(value);
+
+ if (!~exports.indexOf(['object', 'array', 'function'], type)) {
+ if(type != 'buffer') {
+ return jsonStringify(value);
+ }
+ var json = value.toJSON();
+ // Based on the toJSON result
+ return jsonStringify(json.data && json.type ? json.data : json, 2)
+ .replace(/,(\n|$)/g, '$1');
+ }
+
+ for (var prop in value) {
+ if (Object.prototype.hasOwnProperty.call(value, prop)) {
+ return jsonStringify(exports.canonicalize(value), 2).replace(/,(\n|$)/g, '$1');
+ }
+ }
+
+ return emptyRepresentation(value, type);
};
/**
- * Return a new object that has the keys in sorted order.
- * @param {Object} obj
- * @param {Array} [stack]
- * @return {Object}
+ * @description
+ * like JSON.stringify but more sense.
+ * @param {Object} object
+ * @param {Number=} spaces
+ * @param {number=} depth
+ * @returns {*}
+ * @private
+ */
+function jsonStringify(object, spaces, depth) {
+ if(typeof spaces == 'undefined') return _stringify(object); // primitive types
+
+ depth = depth || 1;
+ var space = spaces * depth
+ , str = isArray(object) ? '[' : '{'
+ , end = isArray(object) ? ']' : '}'
+ , length = object.length || exports.keys(object).length
+ , repeat = function(s, n) { return new Array(n).join(s); }; // `.repeat()` polyfill
+
+ function _stringify(val) {
+ switch (exports.type(val)) {
+ case 'null':
+ case 'undefined':
+ val = '[' + val + ']';
+ break;
+ case 'array':
+ case 'object':
+ val = jsonStringify(val, spaces, depth + 1);
+ break;
+ case 'boolean':
+ case 'regexp':
+ case 'number':
+ val = val === 0 && (1/val) === -Infinity // `-0`
+ ? '-0'
+ : val.toString();
+ break;
+ case 'date':
+ var sDate = isNaN(val.getTime()) // Invalid date
+ ? val.toString()
+ : val.toISOString();
+ val = '[Date: ' + sDate + ']';
+ break;
+ case 'buffer':
+ var json = val.toJSON();
+ // Based on the toJSON result
+ json = json.data && json.type ? json.data : json;
+ val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
+ break;
+ default:
+ val = (val == '[Function]' || val == '[Circular]')
+ ? val
+ : JSON.stringify(val); //string
+ }
+ return val;
+ }
+
+ for(var i in object) {
+ if(!object.hasOwnProperty(i)) continue; // not my business
+ --length;
+ str += '\n ' + repeat(' ', space)
+ + (isArray(object) ? '' : '"' + i + '": ') // key
+ + _stringify(object[i]) // value
+ + (length ? ',' : ''); // comma
+ }
+
+ return str + (str.length != 1 // [], {}
+ ? '\n' + repeat(' ', --space) + end
+ : end);
+}
+
+/**
+ * Return if obj is a Buffer
+ * @param {Object} arg
+ * @return {Boolean}
* @api private
*/
+exports.isBuffer = function (arg) {
+ return typeof Buffer !== 'undefined' && Buffer.isBuffer(arg);
+};
-exports.canonicalize = function(obj, stack) {
- stack = stack || [];
+/**
+ * @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
+ */
- if (exports.indexOf(stack, obj) !== -1) return '[Circular]';
+exports.canonicalize = function(value, stack) {
+ var canonicalizedObj,
+ type = exports.type(value),
+ prop,
+ withStack = function withStack(value, fn) {
+ stack.push(value);
+ fn();
+ stack.pop();
+ };
- var canonicalizedObj;
+ stack = stack || [];
- if ({}.toString.call(obj) === '[object Array]') {
- stack.push(obj);
- canonicalizedObj = exports.map(obj, function (item) {
- return exports.canonicalize(item, stack);
- });
- stack.pop();
- } else if (typeof obj === 'object' && obj !== null) {
- stack.push(obj);
- canonicalizedObj = {};
- exports.forEach(exports.keys(obj).sort(), function (key) {
- canonicalizedObj[key] = exports.canonicalize(obj[key], stack);
- });
- stack.pop();
- } else {
- canonicalizedObj = obj;
+ if (exports.indexOf(stack, value) !== -1) {
+ return '[Circular]';
+ }
+
+ switch(type) {
+ case 'undefined':
+ case 'buffer':
+ case 'null':
+ canonicalizedObj = value;
+ break;
+ case 'array':
+ withStack(value, function () {
+ canonicalizedObj = exports.map(value, function (item) {
+ return exports.canonicalize(item, stack);
+ });
+ });
+ break;
+ case 'function':
+ 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 'date':
+ case 'number':
+ case 'regexp':
+ case 'boolean':
+ canonicalizedObj = value;
+ break;
+ default:
+ canonicalizedObj = value.toString();
}
return canonicalizedObj;
- };
+};
/**
* Lookup file names at the given `path`.
@@ -366,7 +601,7 @@ exports.lookupFiles = function lookupFiles(path, extensions, recursive) {
return;
}
- fs.readdirSync(path).forEach(function(file){
+ fs.readdirSync(path).forEach(function(file) {
file = join(path, file);
try {
var stat = fs.statSync(file);
@@ -386,3 +621,90 @@ exports.lookupFiles = function lookupFiles(path, extensions, recursive) {
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();
+};
+
+
+/**
+ * @summary
+ * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
+ * @description
+ * When invoking this function you get a filter function that get the Error.stack as an input,
+ * and return a prettify output.
+ * (i.e: strip Mocha, node_modules, bower and componentJS from stack trace).
+ * @returns {Function}
+ */
+
+exports.stackTraceFilter = function() {
+ var slash = '/'
+ , is = typeof document === 'undefined'
+ ? { node: true }
+ : { browser: true }
+ , cwd = is.node
+ ? process.cwd() + slash
+ : location.href.replace(/\/[^\/]*$/, '/');
+
+ function isNodeModule (line) {
+ return (~line.indexOf('node_modules'));
+ }
+
+ function isMochaInternal (line) {
+ return (~line.indexOf('node_modules' + slash + 'mocha')) ||
+ (~line.indexOf('components' + slash + 'mochajs')) ||
+ (~line.indexOf('components' + slash + 'mocha'));
+ }
+
+ // node_modules, bower, componentJS
+ function isBrowserModule(line) {
+ return (~line.indexOf('node_modules')) ||
+ (~line.indexOf('components'));
+ }
+
+ function isNodeInternal (line) {
+ return (~line.indexOf('(timers.js:')) ||
+ (~line.indexOf('(events.js:')) ||
+ (~line.indexOf('(node.js:')) ||
+ (~line.indexOf('(module.js:')) ||
+ (~line.indexOf('GeneratorFunctionPrototype.next (native)')) ||
+ false
+ }
+
+ return function(stack) {
+ stack = stack.split('\n');
+
+ stack = exports.reduce(stack, function(list, line) {
+ if (is.node && (isNodeModule(line) ||
+ isMochaInternal(line) ||
+ isNodeInternal(line)))
+ return list;
+
+ if (is.browser && (isBrowserModule(line)))
+ return list;
+
+ // Clean up cwd(absolute)
+ list.push(line.replace(cwd, ''));
+ return list;
+ }, []);
+
+ return stack.join('\n');
+ }
+};
\ No newline at end of file
diff --git a/media/logo.svg b/media/logo.svg
index 88d3713..1bed0ce 100644
--- a/media/logo.svg
+++ b/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">
+<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/mocha.js b/mocha.js
index e8bee79..5ff1385 100644
--- a/mocha.js
+++ b/mocha.js
@@ -48,7 +48,6 @@ require.relative = function (parent) {
require.register("browser/debug.js", function(module, exports, require){
-
module.exports = function(type){
return function(){
}
@@ -435,17 +434,16 @@ require.register("browser/escape-string-regexp.js", function(module, exports, re
var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
module.exports = function (str) {
- if (typeof str !== 'string') {
- throw new TypeError('Expected a string');
- }
+ if (typeof str !== 'string') {
+ throw new TypeError('Expected a string');
+ }
- return str.replace(matchOperatorsRe, '\\$&');
+ return str.replace(matchOperatorsRe, '\\$&');
};
}); // module: browser/escape-string-regexp.js
require.register("browser/events.js", function(module, exports, require){
-
/**
* Module exports.
*/
@@ -623,6 +621,7 @@ EventEmitter.prototype.emit = function (name) {
return true;
};
+
}); // module: browser/events.js
require.register("browser/fs.js", function(module, exports, require){
@@ -734,28 +733,28 @@ Progress.prototype.draw = function(ctx){
, y = half
, rad = half - 1
, fontSize = this._fontSize;
-
+
ctx.font = fontSize + 'px ' + this._font;
-
+
var angle = Math.PI * 2 * (percent / 100);
ctx.clearRect(0, 0, size, size);
-
+
// outer circle
ctx.strokeStyle = '#9f9f9f';
ctx.beginPath();
ctx.arc(x, y, rad, 0, angle, false);
ctx.stroke();
-
+
// inner circle
ctx.strokeStyle = '#eee';
ctx.beginPath();
ctx.arc(x, y, rad - 1, 0, angle, true);
ctx.stroke();
-
+
// text
var text = this._text || (percent | 0) + '%'
, w = ctx.measureText(text).width;
-
+
ctx.fillText(
text
, x - w / 2 + 1
@@ -767,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;
};
@@ -784,7 +782,6 @@ exports.getWindowSize = function(){
}); // module: browser/tty.js
require.register("context.js", function(module, exports, require){
-
/**
* Expose `Context`.
*/
@@ -855,6 +852,18 @@ Context.prototype.slow = function(ms){
};
/**
+ * Mark a test as skipped.
+ *
+ * @return {Context} self
+ * @api private
+ */
+
+Context.prototype.skip = function(){
+ this.runnable().skip();
+ return this;
+};
+
+/**
* Inspect the context void of `._runnable`.
*
* @return {String}
@@ -872,7 +881,6 @@ Context.prototype.inspect = function(){
}); // module: context.js
require.register("hook.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -929,7 +937,6 @@ Hook.prototype.error = function(err){
}); // module: hook.js
require.register("interfaces/bdd.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -961,38 +968,13 @@ module.exports = function(suite){
suite.on('pre-require', function(context, file, mocha){
- /**
- * Execute before running tests.
- */
-
- context.before = function(name, fn){
- suites[0].beforeAll(name, fn);
- };
-
- /**
- * Execute after running tests.
- */
-
- context.after = function(name, fn){
- suites[0].afterAll(name, fn);
- };
-
- /**
- * Execute before each test case.
- */
-
- context.beforeEach = function(name, fn){
- suites[0].beforeEach(name, fn);
- };
-
- /**
- * Execute after each test case.
- */
-
- context.afterEach = function(name, fn){
- suites[0].afterEach(name, fn);
- };
+ var common = require('./common')(suites, context);
+ context.before = common.before;
+ context.after = common.after;
+ context.beforeEach = common.beforeEach;
+ context.afterEach = common.afterEach;
+ context.run = mocha.options.delay && common.runWithSuite(suite);
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
@@ -1067,13 +1049,75 @@ module.exports = function(suite){
context.it.skip = function(title){
context.it(title);
};
+
});
};
}); // module: interfaces/bdd.js
-require.register("interfaces/exports.js", function(module, exports, require){
+require.register("interfaces/common.js", function(module, exports, require){
+/**
+ * Functions common to more than one interface
+ * @module lib/interfaces/common
+ */
+
+'use strict';
+
+module.exports = function (suites, context) {
+
+ return {
+ /**
+ * This is only present if flag --delay is passed into Mocha. It triggers
+ * root suite execution. Returns a function which runs the root suite.
+ */
+ runWithSuite: function runWithSuite(suite) {
+ return function run() {
+ suite.run();
+ };
+ },
+
+ /**
+ * Execute before running tests.
+ */
+ before: function (name, fn) {
+ suites[0].beforeAll(name, fn);
+ },
+ /**
+ * Execute after running tests.
+ */
+ after: function (name, fn) {
+ suites[0].afterAll(name, fn);
+ },
+
+ /**
+ * Execute before each test case.
+ */
+ beforeEach: function (name, fn) {
+ suites[0].beforeEach(name, fn);
+ },
+
+ /**
+ * Execute after each test case.
+ */
+ afterEach: function (name, fn) {
+ suites[0].afterEach(name, fn);
+ },
+
+ test: {
+ /**
+ * Pending test case.
+ */
+ skip: function (title) {
+ context.test(title);
+ }
+ }
+ }
+};
+
+}); // module: interfaces/common.js
+
+require.register("interfaces/exports.js", function(module, exports, require){
/**
* Module dependencies.
*/
@@ -1139,7 +1183,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');
@@ -1148,7 +1191,6 @@ exports.exports = require('./exports');
}); // module: interfaces/index.js
require.register("interfaces/qunit.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -1188,38 +1230,13 @@ module.exports = function(suite){
suite.on('pre-require', function(context, file, mocha){
- /**
- * Execute before running tests.
- */
-
- context.before = function(name, fn){
- suites[0].beforeAll(name, fn);
- };
-
- /**
- * Execute after running tests.
- */
-
- context.after = function(name, fn){
- suites[0].afterAll(name, fn);
- };
-
- /**
- * Execute before each test case.
- */
-
- context.beforeEach = function(name, fn){
- suites[0].beforeEach(name, fn);
- };
-
- /**
- * Execute after each test case.
- */
-
- context.afterEach = function(name, fn){
- suites[0].afterEach(name, fn);
- };
+ var common = require('./common')(suites, context);
+ context.before = common.before;
+ context.after = common.after;
+ context.beforeEach = common.beforeEach;
+ context.afterEach = common.afterEach;
+ context.run = mocha.options.delay && common.runWithSuite(suite);
/**
* Describe a "suite" with the given `title`.
*/
@@ -1264,20 +1281,14 @@ module.exports = function(suite){
mocha.grep(new RegExp(reString));
};
- /**
- * Pending test case.
- */
+ context.test.skip = common.test.skip;
- context.test.skip = function(title){
- context.test(title);
- };
});
};
}); // module: interfaces/qunit.js
require.register("interfaces/tdd.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -1317,38 +1328,13 @@ module.exports = function(suite){
suite.on('pre-require', function(context, file, mocha){
- /**
- * Execute before each test case.
- */
-
- context.setup = function(name, fn){
- suites[0].beforeEach(name, fn);
- };
-
- /**
- * Execute after each test case.
- */
-
- context.teardown = function(name, fn){
- suites[0].afterEach(name, fn);
- };
-
- /**
- * Execute before the suite.
- */
-
- context.suiteSetup = function(name, fn){
- suites[0].beforeAll(name, fn);
- };
-
- /**
- * Execute after the suite.
- */
-
- context.suiteTeardown = function(name, fn){
- suites[0].afterAll(name, fn);
- };
+ var common = require('./common')(suites, context);
+ context.setup = common.beforeEach;
+ context.teardown = common.afterEach;
+ context.suiteSetup = common.before;
+ context.suiteTeardown = common.after;
+ context.run = mocha.options.delay && common.runWithSuite(suite);
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
@@ -1409,13 +1395,7 @@ module.exports = function(suite){
mocha.grep(new RegExp(reString));
};
- /**
- * Pending test case.
- */
-
- context.test.skip = function(title){
- context.test(title);
- };
+ context.test.skip = common.test.skip;
});
};
@@ -1490,6 +1470,7 @@ function image(name) {
* - `bail` bail on the first test failure
* - `slow` milliseconds to wait before considering a test slow
* - `ignoreLeaks` ignore global leaks
+ * - `fullTrace` display the full stack-trace on failing
* - `grep` string or regexp to filter tests with
*
* @param {Object} options
@@ -1500,13 +1481,14 @@ function Mocha(options) {
options = options || {};
this.files = [];
this.options = options;
- this.grep(options.grep);
+ if (options.grep) this.grep(new RegExp(options.grep));
+ if (options.fgrep) this.grep(options.fgrep);
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)
+ this.useColors(options.useColors);
if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts);
if (options.slow) this.slow(options.slow);
@@ -1523,6 +1505,7 @@ function Mocha(options) {
exports.suite = context.suite || context.describe;
exports.teardown = context.teardown || context.afterEach;
exports.test = context.test || context.it;
+ exports.run = context.run;
});
}
@@ -1555,17 +1538,21 @@ Mocha.prototype.addFile = function(file){
* 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 || 'spec';
var _reporter;
- try { _reporter = require('./reporters/' + reporter); } catch (err) {};
- if (!_reporter) try { _reporter = require(reporter); } catch (err) {};
+ try { _reporter = require('./reporters/' + reporter); } catch (err) {}
+ if (!_reporter) try { _reporter = require(reporter); } catch (err) {
+ err.message.indexOf('Cannot find module') !== -1
+ ? console.warn('"' + reporter + '" reporter not found')
+ : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack);
+ }
if (!_reporter && reporter === 'teamcity')
console.warn('The Teamcity reporter was moved to a package named ' +
'mocha-teamcity-reporter ' +
@@ -1573,6 +1560,7 @@ Mocha.prototype.reporter = function(reporter){
if (!_reporter) throw new Error('invalid reporter "' + reporter + '"');
this._reporter = _reporter;
}
+ this.options.reporterOptions = reporterOptions;
return this;
};
@@ -1586,7 +1574,7 @@ Mocha.prototype.reporter = function(reporter){
Mocha.prototype.ui = function(name){
name = name || 'bdd';
this._ui = exports.interfaces[name];
- if (!this._ui) try { this._ui = require(name); } catch (err) {};
+ if (!this._ui) try { this._ui = require(name); } catch (err) {}
if (!this._ui) throw new Error('invalid interface "' + name + '"');
this._ui = this._ui(this.suite);
return this;
@@ -1688,6 +1676,18 @@ Mocha.prototype.checkLeaks = function(){
};
/**
+ * Display long stack-trace on failing
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.fullTrace = function() {
+ this.options.fullStackTrace = true;
+ return this;
+};
+
+/**
* Enable growl support.
*
* @return {Mocha}
@@ -1721,9 +1721,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;
};
@@ -1806,28 +1806,47 @@ Mocha.prototype.noHighlighting = function() {
};
/**
+ * Delay root suite execution.
+ * @returns {Mocha}
+ * @api public
+ */
+Mocha.prototype.delay = function delay() {
+ this.options.delay = true;
+ return this;
+};
+
+/**
* Run tests and invoke `fn()` when complete.
*
* @param {Function} fn
* @return {Runner}
* @api public
*/
-
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 runner = new exports.Runner(suite, options.delay);
var reporter = new this._reporter(runner, options);
runner.ignoreLeaks = false !== options.ignoreLeaks;
+ runner.fullStackTrace = options.fullStackTrace;
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 && fn(failures);
+ }
+
+ return runner.run(done);
};
}); // module: mocha.js
@@ -1945,8 +1964,27 @@ function plural(ms, n, name) {
}); // module: ms.js
-require.register("reporters/base.js", function(module, exports, require){
+require.register("pending.js", function(module, exports, require){
+
+/**
+ * Expose `Pending`.
+ */
+module.exports = Pending;
+
+/**
+ * Initialize a new `Pending` error with the given message.
+ *
+ * @param {String} message
+ */
+
+function Pending(message) {
+ this.message = message;
+}
+
+}); // module: pending.js
+
+require.register("reporters/base.js", function(module, exports, require){
/**
* Module dependencies.
*/
@@ -1954,7 +1992,8 @@ require.register("reporters/base.js", function(module, exports, require){
var tty = require('browser/tty')
, diff = require('browser/diff')
, ms = require('../ms')
- , utils = require('../utils');
+ , utils = require('../utils')
+ , supportsColor = process.env ? require('supports-color') : null;
/**
* Save timer references to avoid Sinon interfering (see GH-237).
@@ -1979,10 +2018,12 @@ var isatty = tty.isatty(1) && tty.isatty(2);
exports = module.exports = Base;
/**
- * Enable coloring by default.
+ * Enable coloring by default, except in the browser interface.
*/
-exports.useColors = isatty || (process.env.MOCHA_COLORS !== undefined);
+exports.useColors = process.env
+ ? (supportsColor || (process.env.MOCHA_COLORS !== undefined))
+ : false;
/**
* Inline diffs instead of +/-
@@ -2046,7 +2087,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';
};
@@ -2103,7 +2144,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')
@@ -2114,26 +2155,33 @@ exports.list = function(failures){
var err = test.err
, message = err.message || ''
, stack = err.stack || message
- , index = stack.indexOf(message) + message.length
- , msg = stack.slice(0, index)
+ , index = stack.indexOf(message)
, actual = err.actual
, expected = err.expected
, escape = true;
+ if (index === -1) {
+ msg = message;
+ } else {
+ index += message.length;
+ msg = stack.slice(0, index);
+ // remove msg from stack
+ stack = stack.slice(index + 1);
+ }
// uncaught
if (err.uncaught) {
msg = 'Uncaught ' + msg;
}
-
// explicitly show diff
- if (err.showDiff && sameType(actual, expected)) {
- escape = false;
- err.actual = actual = utils.stringify(actual);
- err.expected = expected = utils.stringify(expected);
- }
+ if (err.showDiff !== false && sameType(actual, expected)
+ && expected !== undefined) {
+
+ if ('string' !== typeof actual) {
+ escape = false;
+ err.actual = actual = utils.stringify(actual);
+ err.expected = expected = utils.stringify(expected);
+ }
- // actual / expected diff
- if (err.showDiff && 'string' == typeof actual && 'string' == typeof expected) {
fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
var match = message.match(/^([^:]+): expected/);
msg = '\n ' + color('error message', match ? match[1] : msg);
@@ -2145,11 +2193,10 @@ exports.list = function(failures){
}
}
- // indent stack trace without msg
- stack = stack.slice(index ? index + 1 : index)
- .replace(/^/gm, ' ');
+ // indent stack trace
+ stack = stack.replace(/^/gm, ' ');
- console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
+ console.log(fmt, (i + 1), test.fullTitle(), msg, stack);
});
};
@@ -2254,11 +2301,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();
@@ -2336,7 +2382,7 @@ function unifiedDiff(err, escape) {
function notBlank(line) {
return line != null;
}
- msg = diff.createPatch('string', err.actual, err.expected);
+ var msg = diff.createPatch('string', err.actual, err.expected);
var lines = msg.split('\n').splice(4);
return '\n '
+ colorLines('diff added', '+ expected') + ' '
@@ -2409,7 +2455,6 @@ function sameType(a, b) {
}); // module: reporters/base.js
require.register("reporters/doc.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -2476,7 +2521,6 @@ function Doc(runner) {
}); // module: reporters/doc.js
require.register("reporters/dot.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -2506,7 +2550,7 @@ function Dot(runner) {
, n = -1;
runner.on('start', function(){
- process.stdout.write('\n ');
+ process.stdout.write('\n');
});
runner.on('pending', function(test){
@@ -2547,7 +2591,6 @@ Dot.prototype.constructor = Dot;
}); // module: reporters/dot.js
require.register("reporters/html-cov.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -2598,10 +2641,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.
*/
@@ -2739,7 +2782,7 @@ function HTML(runner) {
} 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
@@ -2781,13 +2824,28 @@ function HTML(runner) {
}
/**
+ * 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;
+
+ // Remove previous grep query parameter if present
+ if (search) {
+ search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?');
+ }
+
+ 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());
};
/**
@@ -2797,7 +2855,7 @@ HTML.prototype.suiteURL = function(suite){
*/
HTML.prototype.testURL = function(test){
- return '?grep=' + encodeURIComponent(test.fullTitle());
+ return makeUrl(test.fullTitle());
};
/**
@@ -2878,7 +2936,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');
@@ -2900,7 +2957,6 @@ exports.JSONStream = require('./json-stream');
}); // module: reporters/index.js
require.register("reporters/json-cov.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -3057,7 +3113,6 @@ function clean(test) {
}); // module: reporters/json-cov.js
require.register("reporters/json-stream.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -3094,7 +3149,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(){
@@ -3118,10 +3175,10 @@ function clean(test) {
, duration: test.duration
}
}
+
}); // module: reporters/json-stream.js
require.register("reporters/json.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -3218,7 +3275,6 @@ function errorJSON(err) {
}); // module: reporters/json.js
require.register("reporters/landing.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -3276,7 +3332,7 @@ function Landing(runner) {
}
runner.on('start', function(){
- stream.write('\n ');
+ stream.write('\n\n\n ');
cursor.hide();
});
@@ -3293,7 +3349,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('⋅')));
@@ -3319,10 +3375,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.
*/
@@ -3402,6 +3458,12 @@ var Base = require('./base')
, utils = require('../utils');
/**
+ * Constants
+ */
+
+var SUITE_PREFIX = '$';
+
+/**
* Expose `Markdown`.
*/
@@ -3431,8 +3493,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);
});
@@ -3445,11 +3508,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;
}
@@ -3485,10 +3550,10 @@ function Markdown(runner) {
process.stdout.write(buf);
});
}
+
}); // module: reporters/markdown.js
require.register("reporters/min.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -3538,8 +3603,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`.
@@ -3616,17 +3680,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);
@@ -3676,26 +3739,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');
@@ -3776,6 +3839,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';
@@ -3902,7 +3967,6 @@ Progress.prototype.constructor = Progress;
}); // module: reporters/progress.js
require.register("reporters/spec.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -3959,14 +4023,14 @@ function Spec(runner) {
if ('fast' == test.speed) {
var fmt = indent()
+ color('checkmark', ' ' + Base.symbols.ok)
- + color('pass', ' %s ');
+ + color('pass', ' %s');
cursor.CR();
console.log(fmt, test.title);
} else {
var fmt = indent()
+ color('checkmark', ' ' + Base.symbols.ok)
- + color('pass', ' %s ')
- + color(test.speed, '(%dms)');
+ + color('pass', ' %s')
+ + color(test.speed, ' (%dms)');
cursor.CR();
console.log(fmt, test.title, test.duration);
}
@@ -3993,7 +4057,6 @@ Spec.prototype.constructor = Spec;
}); // module: reporters/spec.js
require.register("reporters/tap.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -4070,13 +4133,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;
/**
@@ -4102,12 +4165,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);
});
@@ -4121,7 +4191,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
@@ -4131,12 +4201,25 @@ 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`.
*/
@@ -4147,10 +4230,21 @@ 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
@@ -4159,13 +4253,13 @@ function test(test) {
if ('failed' == test.state) {
var err = test.err;
- console.log(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + 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.
@@ -4196,14 +4290,15 @@ 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');
+ , Pending = require('./pending')
+ , milliseconds = require('./ms')
+ , utils = require('./utils');
/**
* Save timer references to avoid Sinon interfering (see GH-237).
@@ -4244,6 +4339,7 @@ function Runnable(title, fn) {
this._slow = 75;
this._enableTimeouts = true;
this.timedOut = false;
+ this._trace = new Error('done() called multiple times')
}
/**
@@ -4306,6 +4402,16 @@ Runnable.prototype.enableTimeouts = function(enabled){
};
/**
+ * Halt and mark as pending.
+ *
+ * @api private
+ */
+
+Runnable.prototype.skip = function(){
+ throw new Pending();
+};
+
+/**
* Return the full title generated by recursively
* concatenating the parent's full title.
*
@@ -4357,7 +4463,7 @@ Runnable.prototype.resetTimeout = function(){
this.clearTimeout();
this.timer = setTimeout(function(){
if (!self._enableTimeouts) return;
- self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
+ self.callback(new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'));
self.timedOut = true;
}, ms);
};
@@ -4393,18 +4499,22 @@ Runnable.prototype.run = function(fn){
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);
+
+ // Discard the resolution if this test has already failed asynchronously
+ if (self.state) return;
+
self.clearTimeout();
self.duration = new Date - start;
finished = true;
- if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded');
+ if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.');
fn(err);
}
@@ -4428,7 +4538,7 @@ Runnable.prototype.run = function(fn){
done();
});
} catch (err) {
- done(err);
+ done(utils.getError(err));
}
return;
}
@@ -4445,7 +4555,7 @@ Runnable.prototype.run = function(fn){
callFn(this.fn);
}
} catch (err) {
- done(err);
+ done(utils.getError(err));
}
function callFn(fn) {
@@ -4474,10 +4584,14 @@ require.register("runner.js", function(module, exports, require){
var EventEmitter = require('browser/events').EventEmitter
, debug = require('browser/debug')('mocha:runner')
+ , Pending = require('./pending')
, Test = require('./test')
, utils = require('./utils')
, filter = utils.filter
- , keys = utils.keys;
+ , keys = utils.keys
+ , type = utils.type
+ , stringify = utils.stringify
+ , stackFilter = utils.stackTraceFilter();
/**
* Non-enumerable globals.
@@ -4489,7 +4603,9 @@ var globals = [
'setInterval',
'clearInterval',
'XMLHttpRequest',
- 'Date'
+ 'Date',
+ 'setImmediate',
+ 'clearImmediate'
];
/**
@@ -4515,13 +4631,17 @@ module.exports = Runner;
* - `fail` (test, err) test failed
* - `pending` (test) test pending
*
+ * @param {Suite} suite Root suite
+ * @param {boolean} [delay] Whether or not to delay execution of root suite
+ * until ready.
* @api public
*/
-function Runner(suite) {
+function Runner(suite, delay) {
var self = this;
this._globals = [];
this._abort = false;
+ this._delay = delay;
this.suite = suite;
this.total = suite.total();
this.failures = 0;
@@ -4662,14 +4782,18 @@ Runner.prototype.checkGlobals = function(test){
* @api private
*/
-Runner.prototype.fail = function(test, err){
+Runner.prototype.fail = function(test, err) {
++this.failures;
test.state = 'failed';
- if ('string' == typeof err) {
- err = new Error('the string "' + err + '" was thrown, throw an Error :)');
+ if (!(err instanceof Error)) {
+ err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)');
}
+ err.stack = (this.fullStackTrace || !err.stack)
+ ? err.stack
+ : stackFilter(err.stack);
+
this.emit('fail', test, err);
};
@@ -4718,7 +4842,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;
@@ -4734,10 +4857,14 @@ Runner.prototype.hook = function(name, fn){
var testError = hook.error();
if (testError) self.fail(self.test, testError);
if (err) {
- self.failHook(hook, err);
+ if (err instanceof Pending) {
+ suite.pending = true;
+ } else {
+ self.failHook(hook, err);
- // stop executing hooks, notify callee of hook err
- return fn(err);
+ // stop executing hooks, notify callee of hook err
+ return fn(err);
+ }
}
self.emit('hook end', hook);
delete hook.ctx.currentTest;
@@ -4919,6 +5046,11 @@ Runner.prototype.runTests = function(suite, fn){
self.emit('test', self.test = test);
self.hookDown('beforeEach', function(err, errSuite){
+ if (suite.pending) {
+ self.emit('pending', test);
+ self.emit('test end', test);
+ return next();
+ }
if (err) return hookErr(err, errSuite, false);
self.currentRunnable = self.test;
@@ -4926,8 +5058,17 @@ Runner.prototype.runTests = function(suite, fn){
test = self.test;
if (err) {
- self.fail(test, err);
+ if (err instanceof Pending) {
+ self.emit('pending', test);
+ } else {
+ self.fail(test, err);
+ }
self.emit('test end', test);
+
+ if (err instanceof Pending) {
+ return next();
+ }
+
return self.hookUp('afterEach', next);
}
@@ -5012,19 +5153,18 @@ Runner.prototype.uncaught = function(err){
}.call(err) ? err : ( err.message || err ));
} else {
debug('uncaught undefined exception');
- err = new Error('Caught undefined error, did you throw without specifying what?');
+ 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;
+ // Ignore errors if complete
+ if (runnable.state) return;
+ this.fail(runnable, err);
// recover from test
if ('test' == runnable.type) {
@@ -5047,13 +5187,23 @@ Runner.prototype.uncaught = function(err){
*/
Runner.prototype.run = function(fn){
- var self = this
- , fn = fn || function(){};
+ var self = this,
+ rootSuite = this.suite;
+
+ fn = fn || function(){};
function uncaught(err){
self.uncaught(err);
}
+ function start() {
+ self.emit('start');
+ self.runSuite(rootSuite, function(){
+ debug('finished running');
+ self.emit('end');
+ });
+ }
+
debug('start');
// callback
@@ -5063,16 +5213,19 @@ Runner.prototype.run = function(fn){
fn(self.failures);
});
- // run suites
- this.emit('start');
- this.runSuite(this.suite, function(){
- debug('finished running');
- self.emit('end');
- });
-
// uncaught exception
process.on('uncaughtException', uncaught);
+ if (this._delay) {
+ // for reporters, I guess.
+ // might be nice to debounce some dots while we wait.
+ this.emit('waiting', rootSuite);
+ rootSuite.once('run', start);
+ }
+ else {
+ start();
+ }
+
return this;
};
@@ -5128,28 +5281,27 @@ function filterLeaks(ok, globals) {
* @api private
*/
- function extraGlobals() {
- if (typeof(process) === 'object' &&
- typeof(process.version) === 'string') {
+function extraGlobals() {
+ if (typeof(process) === 'object' &&
+ typeof(process.version) === 'string') {
- var nodeVersion = process.version.split('.').reduce(function(a, v) {
- return a << 8 | v;
- });
+ var nodeVersion = process.version.split('.').reduce(function(a, v) {
+ return a << 8 | v;
+ });
- // 'errno' was renamed to process._errno in v0.9.11.
+ // 'errno' was renamed to process._errno in v0.9.11.
- if (nodeVersion < 0x00090B) {
- return ['errno'];
- }
- }
-
- return [];
+ if (nodeVersion < 0x00090B) {
+ return ['errno'];
+ }
}
+ return [];
+}
+
}); // module: runner.js
require.register("suite.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -5214,6 +5366,7 @@ function Suite(title, parentContext) {
this._enableTimeouts = true;
this._slow = 75;
this._bail = false;
+ this.delayed = false;
}
/**
@@ -5254,7 +5407,7 @@ Suite.prototype.clone = function(){
Suite.prototype.timeout = function(ms){
if (0 == arguments.length) return this._timeout;
- if (ms === 0) this._enableTimeouts = false;
+ if (ms.toString() === '0') this._enableTimeouts = false;
if ('string' == typeof ms) ms = milliseconds(ms);
debug('timeout %d', ms);
this._timeout = parseInt(ms, 10);
@@ -5295,7 +5448,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
*/
@@ -5500,10 +5653,18 @@ Suite.prototype.eachTest = function(fn){
return this;
};
+/**
+ * This will run the root suite if we happen to be running in delayed mode.
+ */
+Suite.prototype.run = function run() {
+ if (this.root) {
+ this.emit('run');
+ }
+};
+
}); // module: suite.js
require.register("test.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -5603,7 +5764,7 @@ exports.forEach = function(arr, fn, scope){
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));
+ result.push(fn.call(scope, arr[i], i, arr));
return result;
};
@@ -5672,7 +5833,7 @@ exports.filter = function(arr, fn){
exports.keys = Object.keys || function(obj) {
var keys = []
- , has = Object.prototype.hasOwnProperty // for `window` on <=IE8
+ , has = Object.prototype.hasOwnProperty; // for `window` on <=IE8
for (var key in obj) {
if (has.call(obj, key)) {
@@ -5703,6 +5864,28 @@ exports.watch = function(files, fn){
};
/**
+ * Array.isArray (<=IE8)
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+var isArray = Array.isArray || function (obj) {
+ return '[object Array]' == {}.toString.call(obj);
+};
+
+/**
+ * @description
+ * Buffer.prototype.toJSON polyfill
+ * @type {Function}
+ */
+if(typeof Buffer !== 'undefined' && Buffer.prototype) {
+ Buffer.prototype.toJSON = Buffer.prototype.toJSON || function () {
+ return Array.prototype.slice.call(this, 0);
+ };
+}
+
+/**
* Ignored files.
*/
@@ -5724,15 +5907,15 @@ exports.files = function(dir, ext, ret){
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);
- }
- });
+ .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;
};
@@ -5760,7 +5943,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 *\(.*\)\s*{|\(.*\) *=> *{?/, '')
.replace(/\s+\}$/, '');
var spaces = str.match(/^\n?( *)/)[1].length
@@ -5837,54 +6020,253 @@ exports.highlightTags = function(name) {
}
};
+/**
+ * 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();
+};
/**
- * Stringify `obj`.
+ * @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().
*
- * @param {Object} obj
- * @return {String}
+ * @see exports.type
+ * @param {*} value
+ * @return {string}
* @api private
*/
-exports.stringify = function(obj) {
- if (obj instanceof RegExp) return obj.toString();
- return JSON.stringify(exports.canonicalize(obj), null, 2).replace(/,(\n|$)/g, '$1');
+exports.stringify = function(value) {
+ var type = exports.type(value);
+
+ if (!~exports.indexOf(['object', 'array', 'function'], type)) {
+ if(type != 'buffer') {
+ return jsonStringify(value);
+ }
+ var json = value.toJSON();
+ // Based on the toJSON result
+ return jsonStringify(json.data && json.type ? json.data : json, 2)
+ .replace(/,(\n|$)/g, '$1');
+ }
+
+ for (var prop in value) {
+ if (Object.prototype.hasOwnProperty.call(value, prop)) {
+ return jsonStringify(exports.canonicalize(value), 2).replace(/,(\n|$)/g, '$1');
+ }
+ }
+
+ return emptyRepresentation(value, type);
+};
+
+/**
+ * @description
+ * like JSON.stringify but more sense.
+ * @param {Object} object
+ * @param {Number=} spaces
+ * @param {number=} depth
+ * @returns {*}
+ * @private
+ */
+function jsonStringify(object, spaces, depth) {
+ if(typeof spaces == 'undefined') return _stringify(object); // primitive types
+
+ depth = depth || 1;
+ var space = spaces * depth
+ , str = isArray(object) ? '[' : '{'
+ , end = isArray(object) ? ']' : '}'
+ , length = object.length || exports.keys(object).length
+ , repeat = function(s, n) { return new Array(n).join(s); }; // `.repeat()` polyfill
+
+ function _stringify(val) {
+ switch (exports.type(val)) {
+ case 'null':
+ case 'undefined':
+ val = '[' + val + ']';
+ break;
+ case 'array':
+ case 'object':
+ val = jsonStringify(val, spaces, depth + 1);
+ break;
+ case 'boolean':
+ case 'regexp':
+ case 'number':
+ val = val === 0 && (1/val) === -Infinity // `-0`
+ ? '-0'
+ : val.toString();
+ break;
+ case 'date':
+ val = '[Date: ' + val.toISOString() + ']';
+ break;
+ case 'buffer':
+ var json = val.toJSON();
+ // Based on the toJSON result
+ json = json.data && json.type ? json.data : json;
+ val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
+ break;
+ default:
+ val = (val == '[Function]' || val == '[Circular]')
+ ? val
+ : '"' + val + '"'; //string
+ }
+ return val;
+ }
+
+ for(var i in object) {
+ if(!object.hasOwnProperty(i)) continue; // not my business
+ --length;
+ str += '\n ' + repeat(' ', space)
+ + (isArray(object) ? '' : '"' + i + '": ') // key
+ + _stringify(object[i]) // value
+ + (length ? ',' : ''); // comma
+ }
+
+ return str + (str.length != 1 // [], {}
+ ? '\n' + repeat(' ', --space) + end
+ : end);
+}
+
+/**
+ * Return if obj is a Buffer
+ * @param {Object} arg
+ * @return {Boolean}
+ * @api private
+ */
+exports.isBuffer = function (arg) {
+ return typeof Buffer !== 'undefined' && Buffer.isBuffer(arg);
};
/**
- * Return a new object that has the keys in sorted order.
- * @param {Object} obj
- * @param {Array} [stack]
- * @return {Object}
+ * @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(obj, stack) {
- stack = stack || [];
+exports.canonicalize = function(value, stack) {
+ var canonicalizedObj,
+ type = exports.type(value),
+ prop,
+ withStack = function withStack(value, fn) {
+ stack.push(value);
+ fn();
+ stack.pop();
+ };
- if (exports.indexOf(stack, obj) !== -1) return '[Circular]';
+ stack = stack || [];
- var canonicalizedObj;
+ if (exports.indexOf(stack, value) !== -1) {
+ return '[Circular]';
+ }
- if ({}.toString.call(obj) === '[object Array]') {
- stack.push(obj);
- canonicalizedObj = exports.map(obj, function (item) {
- return exports.canonicalize(item, stack);
- });
- stack.pop();
- } else if (typeof obj === 'object' && obj !== null) {
- stack.push(obj);
- canonicalizedObj = {};
- exports.forEach(exports.keys(obj).sort(), function (key) {
- canonicalizedObj[key] = exports.canonicalize(obj[key], stack);
- });
- stack.pop();
- } else {
- canonicalizedObj = obj;
+ switch(type) {
+ case 'undefined':
+ case 'buffer':
+ case 'null':
+ canonicalizedObj = value;
+ break;
+ case 'array':
+ withStack(value, function () {
+ canonicalizedObj = exports.map(value, function (item) {
+ return exports.canonicalize(item, stack);
+ });
+ });
+ break;
+ case 'function':
+ 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 'date':
+ case 'number':
+ case 'regexp':
+ case 'boolean':
+ canonicalizedObj = value;
+ break;
+ default:
+ canonicalizedObj = value.toString();
}
return canonicalizedObj;
- };
+};
/**
* Lookup file names at the given `path`.
@@ -5911,7 +6293,7 @@ exports.lookupFiles = function lookupFiles(path, extensions, recursive) {
return;
}
- fs.readdirSync(path).forEach(function(file){
+ fs.readdirSync(path).forEach(function(file) {
file = join(path, file);
try {
var stat = fs.statSync(file);
@@ -5932,6 +6314,92 @@ exports.lookupFiles = function lookupFiles(path, extensions, recursive) {
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();
+};
+
+
+/**
+ * @summary
+ * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
+ * @description
+ * When invoking this function you get a filter function that get the Error.stack as an input,
+ * and return a prettify output.
+ * (i.e: strip Mocha, node_modules, bower and componentJS from stack trace).
+ * @returns {Function}
+ */
+
+exports.stackTraceFilter = function() {
+ var slash = '/'
+ , is = typeof document === 'undefined'
+ ? { node: true }
+ : { browser: true }
+ , cwd = is.node
+ ? process.cwd() + slash
+ : location.href.replace(/\/[^\/]*$/, '/');
+
+ function isNodeModule (line) {
+ return (~line.indexOf('node_modules'));
+ }
+
+ function isMochaInternal (line) {
+ return (~line.indexOf('node_modules' + slash + 'mocha')) ||
+ (~line.indexOf('components' + slash + 'mochajs')) ||
+ (~line.indexOf('components' + slash + 'mocha'));
+ }
+
+ // node_modules, bower, componentJS
+ function isBrowserModule(line) {
+ return (~line.indexOf('node_modules')) ||
+ (~line.indexOf('components'));
+ }
+
+ function isNodeInternal (line) {
+ return (~line.indexOf('(timers.js:')) ||
+ (~line.indexOf('(events.js:')) ||
+ (~line.indexOf('(node.js:')) ||
+ (~line.indexOf('(module.js:')) ||
+ (~line.indexOf('GeneratorFunctionPrototype.next (native)')) ||
+ false
+ }
+
+ return function(stack) {
+ stack = stack.split('\n');
+
+ stack = exports.reduce(stack, function(list, line) {
+ if (is.node && (isNodeModule(line) ||
+ isMochaInternal(line) ||
+ isNodeInternal(line)))
+ return list;
+
+ if (is.browser && (isBrowserModule(line)))
+ return list;
+
+ // Clean up cwd(absolute)
+ list.push(line.replace(cwd, ''));
+ return list;
+ }, []);
+
+ return stack.join('\n');
+ }
+};
}); // module: utils.js
// The global object is "self" in Web Workers.
var global = (function() { return this; })();
@@ -6074,7 +6542,8 @@ mocha.run = function(fn){
mocha.globals('location');
var query = Mocha.utils.parseQuery(global.location.search || '');
- if (query.grep) mocha.grep(query.grep);
+ if (query.grep) mocha.grep(new RegExp(query.grep));
+ if (query.fgrep) mocha.grep(query.fgrep);
if (query.invert) mocha.invert();
return Mocha.prototype.run.call(mocha, function(err){
@@ -6092,4 +6561,4 @@ mocha.run = function(fn){
*/
Mocha.process = process;
-})();
\ No newline at end of file
+})();
diff --git a/package.json b/package.json
index ce702d2..28e16ff 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mocha",
- "version": "1.21.5",
+ "version": "2.2.5",
"description": "simple, flexible, fun test framework",
"keywords": [
"mocha",
@@ -12,17 +12,24 @@
"author": "TJ Holowaychuk <tj at vision-media.ca>",
"contributors": [
"Joshua Appelman <joshua at jbna.nl>",
- "Oleg Gaidarenko <markelog at gmail.com>",
"Christoffer Hallas <christoffer.hallas at gmail.com>",
"Christopher Hiller <chiller at badwing.com>",
"Travis Jeffery <tj at travisjeffery.com>",
- "Johnathan Ong <me at jongleberry.com>",
- "Guillermo Rauch <rauchg at gmail.com>"
+ "Daniel St. Jules <danielst.jules at gmail.com>",
+ "David da Silva Contín <dasilvacontin at gmail.com>",
+ "Ariel Mashraki <ariel at mashraki.co.il>",
+ "Pawel Kozlowski <pkozlowski.opensource at gmail.com>"
],
+ "license": "MIT",
"repository": {
"type": "git",
- "url": "git://github.com/visionmedia/mocha.git"
+ "url": "git://github.com/mochajs/mocha.git"
},
+ "maintainers": [
+ "travisjeffery <tj at travisjeffery.com>",
+ "jbnicolai <joshua at jbna.nl>",
+ "boneskull <chiller at badwing.com>"
+ ],
"main": "./index",
"browser": "./mocha.js",
"bin": {
@@ -30,7 +37,7 @@
"_mocha": "./bin/_mocha"
},
"engines": {
- "node": ">= 0.4.x"
+ "node": ">= 0.8.x"
},
"scripts": {
"test": "make test-all"
@@ -38,12 +45,13 @@
"dependencies": {
"commander": "2.3.0",
"debug": "2.0.0",
- "diff": "1.0.8",
+ "diff": "1.4.0",
"escape-string-regexp": "1.0.2",
"glob": "3.2.3",
"growl": "1.8.1",
"jade": "0.26.3",
- "mkdirp": "0.5.0"
+ "mkdirp": "0.5.0",
+ "supports-color": "~1.2.0"
},
"devDependencies": {
"coffee-script": "~1.8.0",
@@ -61,7 +69,7 @@
"licenses": [
{
"type": "MIT",
- "url": "https://raw.github.com/visionmedia/mocha/master/LICENSE"
+ "url": "https://raw.github.com/mochajs/mocha/master/LICENSE"
}
]
-}
+}
\ No newline at end of file
diff --git a/support/compile.js b/support/compile.js
index a0a94d2..bea017a 100644
--- a/support/compile.js
+++ b/support/compile.js
@@ -1,4 +1,3 @@
-
/**
* Module dependencies.
*/
diff --git a/support/foot.js b/support/foot.js
index 158693a..0319a0f 100644
--- a/support/foot.js
+++ b/support/foot.js
@@ -1 +1 @@
-})();
\ No newline at end of file
+})();
diff --git a/support/tail.js b/support/tail.js
index e9c0c0d..030177a 100644
--- a/support/tail.js
+++ b/support/tail.js
@@ -139,7 +139,8 @@ mocha.run = function(fn){
mocha.globals('location');
var query = Mocha.utils.parseQuery(global.location.search || '');
- if (query.grep) mocha.grep(query.grep);
+ if (query.grep) mocha.grep(new RegExp(query.grep));
+ if (query.fgrep) mocha.grep(query.fgrep);
if (query.invert) mocha.invert();
return Mocha.prototype.run.call(mocha, function(err){
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..47de23e
--- /dev/null
+++ b/test.js
@@ -0,0 +1,9 @@
+function usedToBeAsync (cb) {
+ cb()
+}
+
+it('test', function() {
+ this.timeout(4294967296);
+ usedToBeAsync(done)
+});
+
diff --git a/test/acceptance/context.js b/test/acceptance/context.js
index add011b..47c2db7 100644
--- a/test/acceptance/context.js
+++ b/test/acceptance/context.js
@@ -1,4 +1,3 @@
-
describe('Context', function(){
beforeEach(function(){
this.calls = ['before'];
diff --git a/test/acceptance/diffs.js b/test/acceptance/diffs.js
deleted file mode 100644
index b0b6eae..0000000
--- a/test/acceptance/diffs.js
+++ /dev/null
@@ -1,87 +0,0 @@
-
-var fs = require('fs')
- , cssin = fs.readFileSync('test/acceptance/fixtures/css.in', 'ascii')
- , cssout = fs.readFileSync('test/acceptance/fixtures/css.out', 'ascii');
-
-describe('diffs', function(){
- // uncomment the assertions, and run with different params to check the output
- // ex: --color, --no-color, --unified-diff
-
- it('should display a diff for small strings', function(){
- var expected = 'foo bar baz'
- , actual = 'foo rar baz';
-
- // expected.should.eql(actual);
- });
-
- it('should display a diff of canonicalized objects', function(){
- var actual = { name: 'travis j', age: 23 }
- , expected = { age: 23, name: 'travis' };
-
- // actual.should.eql(expected);
- });
-
- it('should display a diff for medium strings', function(){
- var expected = 'foo bar baz\nfoo bar baz\nfoo bar baz'
- , actual = 'foo bar baz\nfoo rar baz\nfoo bar raz';
-
- // expected.should.eql(actual);
- });
-
- it('should display a diff for entire object dumps', function(){
- var expected = { name: 'joe', age: 30, address: {city: 'new york', country: 'us' }}
- , actual = { name: 'joel', age: 30, address: {city: 'new york', country: 'usa' }};
-
- // actual.should.eql(expected);
- });
-
- it('should display a diff for multi-line strings', function(){
- var expected = 'one two three\nfour five six\nseven eight nine';
- var actual = 'one two three\nfour zzzz six\nseven eight nine';
-
- // actual.should.eql(expected);
- });
-
- it('should display a diff for entire object dumps', function(){
- var expected = { name: 'joe', age: 30, address: {city: 'new york', country: 'us' }}
- var actual = { name: 'joel', age: 30, address: {city: 'new york', country: 'usa' }};
-
- // actual.should.eql(expected);
- });
-
- it('should display a full-comparison with escaped special characters', function(){
- var expected = 'one\ttab\ntwo\t\ttabs';
- var actual = 'one\ttab\ntwo\t\t\ttabs';
-
- //actual.should.equal(expected);
- });
-
- it('should display a word diff for large strings', function(){
- // cssin.should.equal(cssout);
- });
-
- it('should work with objects', function(){
- var tobi = {
- name: 'tobi',
- species: 'ferret',
- color: 'white',
- age: 2
- };
-
- var loki = {
- name: 'loki',
- species: 'ferret',
- color: 'brown',
- age: 2
- };
-
- // 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);
- });
-});
diff --git a/test/acceptance/duration.js b/test/acceptance/duration.js
index 1f4c5c8..4f319b8 100644
--- a/test/acceptance/duration.js
+++ b/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/test/acceptance/failing/timeout.js b/test/acceptance/failing/timeout.js
deleted file mode 100644
index e52dde4..0000000
--- a/test/acceptance/failing/timeout.js
+++ /dev/null
@@ -1,17 +0,0 @@
-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/test/acceptance/fs.js b/test/acceptance/fs.js
index 102b8e1..cdd3216 100644
--- a/test/acceptance/fs.js
+++ b/test/acceptance/fs.js
@@ -1,4 +1,3 @@
-
var fs = require('fs');
describe('fs.readFile()', function(){
diff --git a/test/acceptance/glob/glob.js b/test/acceptance/glob/glob.js
index b1127a2..3029ae8 100644
--- a/test/acceptance/glob/glob.js
+++ b/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/test/acceptance/globals.js b/test/acceptance/globals.js
index 815eaee..f8ef804 100644
--- a/test/acceptance/globals.js
+++ b/test/acceptance/globals.js
@@ -1,4 +1,3 @@
-
describe('global leaks', function(){
before(function(){
// uncomment to test
diff --git a/test/acceptance/http.js b/test/acceptance/http.js
index 00406e6..1dfa914 100644
--- a/test/acceptance/http.js
+++ b/test/acceptance/http.js
@@ -1,4 +1,3 @@
-
var http = require('http');
var server = http.createServer(function(req, res){
@@ -14,4 +13,4 @@ describe('http', function(){
done();
})
})
-})
\ No newline at end of file
+})
diff --git a/test/acceptance/interfaces/bdd.js b/test/acceptance/interfaces/bdd.js
index f536aa0..bea1db2 100644
--- a/test/acceptance/interfaces/bdd.js
+++ b/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/test/acceptance/interfaces/exports.js b/test/acceptance/interfaces/exports.js
index c93bf28..38093d5 100644
--- a/test/acceptance/interfaces/exports.js
+++ b/test/acceptance/interfaces/exports.js
@@ -1,4 +1,3 @@
-
var calls = [];
exports.Array = {
diff --git a/test/acceptance/interfaces/qunit.js b/test/acceptance/interfaces/qunit.js
index dbdc5bb..48aa21d 100644
--- a/test/acceptance/interfaces/qunit.js
+++ b/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/test/acceptance/interfaces/tdd.js b/test/acceptance/interfaces/tdd.js
index 33311dd..1c6885e 100644
--- a/test/acceptance/interfaces/tdd.js
+++ b/test/acceptance/interfaces/tdd.js
@@ -1,4 +1,3 @@
-
suite('Array', function(){
suite('#indexOf()', function(){
var initialValue = 32;
diff --git a/test/acceptance/misc/asyncOnly.js b/test/acceptance/misc/asyncOnly.js
deleted file mode 100644
index e03251f..0000000
--- a/test/acceptance/misc/asyncOnly.js
+++ /dev/null
@@ -1,10 +0,0 @@
-
-describe('asyncOnly', function(){
- it('should display an error', function(){
-
- })
-
- it('should pass', function(done){
- done();
- })
-})
diff --git a/test/acceptance/misc/bail.js b/test/acceptance/misc/bail.js
deleted file mode 100644
index 0628b2f..0000000
--- a/test/acceptance/misc/bail.js
+++ /dev/null
@@ -1,21 +0,0 @@
-
-describe('bail', function(){
- it('should only display this error', function(done){
- throw new Error('this should be displayed');
- })
-
- it('should not display this error', function(done){
- throw new Error('this should not be displayed');
- })
-})
-
-describe('bail-2', function(){
-
- before(function(done){
- throw new Error('this hook should not be displayed');
- })
-
- it('should not display this error', function(done){
- throw new Error('this should not be displayed');
- })
-})
diff --git a/test/acceptance/misc/cascade.js b/test/acceptance/misc/cascade.js
deleted file mode 100644
index 0f884a0..0000000
--- a/test/acceptance/misc/cascade.js
+++ /dev/null
@@ -1,58 +0,0 @@
-
-describe('one', function(){
- before(function(){
- console.log('before one');
- })
-
- after(function(){
- console.log('after one');
- })
-
- beforeEach(function(){
- console.log(' before each one');
- })
-
- afterEach(function(){
- console.log(' after each one');
- })
-
- describe('two', function(){
- before(function(){
- console.log(' before two');
- })
-
- after(function(){
- console.log(' after two');
- })
-
- beforeEach(function(){
- console.log(' before each two');
- })
-
- afterEach(function(){
- console.log(' after each two');
- })
-
- describe('three', function(){
- before(function(){
- console.log(' before three');
- })
-
- after(function(){
- console.log(' after three');
- })
-
- beforeEach(function(){
- console.log(' before each three');
- })
-
- afterEach(function(){
- console.log(' after each three');
- })
-
- it('should three', function(){
- console.log(' TEST three');
- })
- })
- })
-})
diff --git a/test/acceptance/misc/exit.js b/test/acceptance/misc/exit.js
index 4cace0b..113e392 100644
--- a/test/acceptance/misc/exit.js
+++ b/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/test/acceptance/misc/grep.js b/test/acceptance/misc/grep.js
deleted file mode 100644
index 9bfe0c5..0000000
--- a/test/acceptance/misc/grep.js
+++ /dev/null
@@ -1,22 +0,0 @@
-
-describe('grep', function(){
- describe('fast', function(){
- it('should run fast', function(){
-
- })
-
- it('should run fast again', function(){
-
- })
- })
-
- describe('slow', function(){
- it('should run slow', function(done){
- setTimeout(done, 1000);
- })
-
- it('should run slow again', function(done){
- setTimeout(done, 1000);
- })
- })
-})
diff --git a/test/acceptance/misc/many.js b/test/acceptance/misc/many.js
index c479ae4..26538bc 100644
--- a/test/acceptance/misc/many.js
+++ b/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/test/acceptance/misc/nontty.js b/test/acceptance/misc/nontty.js
index cd96f1f..2372a66 100644
--- a/test/acceptance/misc/nontty.js
+++ b/test/acceptance/misc/nontty.js
@@ -1,4 +1,3 @@
-
describe('tests for non-tty', function(){
it('should pass', function(){
diff --git a/test/acceptance/misc/only/bdd.js b/test/acceptance/misc/only/bdd.js
index 56627ab..ff14dcd 100644
--- a/test/acceptance/misc/only/bdd.js
+++ b/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/test/acceptance/misc/only/qunit.js b/test/acceptance/misc/only/qunit.js
index e1d9ac1..07c240f 100644
--- a/test/acceptance/misc/only/qunit.js
+++ b/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/test/acceptance/misc/only/tdd.js b/test/acceptance/misc/only/tdd.js
index ed7e906..cb6429a 100644
--- a/test/acceptance/misc/only/tdd.js
+++ b/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/test/acceptance/multiple.done.js b/test/acceptance/multiple.done.js
deleted file mode 100644
index aeb8845..0000000
--- a/test/acceptance/multiple.done.js
+++ /dev/null
@@ -1,16 +0,0 @@
-
-describe('multiple calls to done()', function(){
- beforeEach(function(done){
- done()
- // uncomment
- // done()
- })
-
- it('should fail in a test-case', function(done){
- process.nextTick(function(){
- done();
- // uncomment
- // done();
- });
- })
-})
\ No newline at end of file
diff --git a/test/acceptance/pending.js b/test/acceptance/pending.js
deleted file mode 100644
index cf738b2..0000000
--- a/test/acceptance/pending.js
+++ /dev/null
@@ -1,4 +0,0 @@
-
-describe('pending', function(){
- it('should be allowed')
-})
\ No newline at end of file
diff --git a/test/acceptance/require/require.js b/test/acceptance/require/require.js
index 74dd0eb..20f3e6d 100644
--- a/test/acceptance/require/require.js
+++ b/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/test/acceptance/root.js b/test/acceptance/root.js
index 49a1e7f..1773830 100644
--- a/test/acceptance/root.js
+++ b/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/test/acceptance/test.coffee b/test/acceptance/test.coffee
index b1c470a..8260940 100644
--- a/test/acceptance/test.coffee
+++ b/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/test/acceptance/throw.js b/test/acceptance/throw.js
new file mode 100644
index 0000000..ac74f22
--- /dev/null
+++ b/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/test/acceptance/timeout.js b/test/acceptance/timeout.js
index a12f2fb..f61c3ba 100644
--- a/test/acceptance/timeout.js
+++ b/test/acceptance/timeout.js
@@ -1,4 +1,3 @@
-
describe('timeouts', function(){
beforeEach(function(done){
// uncomment
diff --git a/test/acceptance/uncaught.js b/test/acceptance/uncaught.js
deleted file mode 100644
index 7349595..0000000
--- a/test/acceptance/uncaught.js
+++ /dev/null
@@ -1,17 +0,0 @@
-
-describe('uncaught', function(){
- beforeEach(function(done){
- process.nextTick(function(){
- // throw new Error('oh noes');
- done();
- });
- })
-
- it('should report properly', function(done){
- process.nextTick(function(){
- // if you uncomment this :)
- // throw new Error("I'm uncaught!");
- done();
- })
- })
-})
\ No newline at end of file
diff --git a/test/acceptance/utils.js b/test/acceptance/utils.js
index 4bb52e3..e67250b 100644
--- a/test/acceptance/utils.js
+++ b/test/acceptance/utils.js
@@ -35,8 +35,8 @@ describe('lib/utils', function () {
it("should format functions saved in windows style - spaces", function () {
var fn = [
"function (one) {"
- , " do {",
- , ' "nothing";',
+ , " do {"
+ , ' "nothing";'
, " } while (false);"
, ' }'
].join("\r\n");
@@ -72,18 +72,280 @@ describe('lib/utils', function () {
});
describe('stringify', function(){
- it('should canoncalize the object', function(){
+
+ var stringify = utils.stringify;
+
+ it('should return Buffer with .toJSON representation', function() {
+ stringify(new Buffer([0x01])).should.equal('[\n 1\n]');
+ stringify(new Buffer([0x01, 0x02])).should.equal('[\n 1\n 2\n]');
+
+ stringify(new Buffer('ABCD')).should.equal('[\n 65\n 66\n 67\n 68\n]');
+ });
+
+ it('should return Date object with .toISOString() + string prefix', function() {
+ stringify(new Date(0)).should.equal('[Date: ' + new Date(0).toISOString() + ']');
+
+ var date = new Date(); // now
+ stringify(date).should.equal('[Date: ' + date.toISOString() + ']');
+ });
+
+ it('should return invalid Date object with .toString() + string prefix', function() {
+ stringify(new Date('')).should.equal('[Date: ' + new Date('').toString() + ']');
+ });
+
+ describe('#Number', function() {
+ it('should show the handle -0 situations', function() {
+ stringify(-0).should.eql('-0');
+ stringify(0).should.eql('0');
+ stringify('-0').should.eql('"-0"');
+ });
+
+ it('should work well with `NaN` and `Infinity`', function() {
+ stringify(NaN).should.equal('NaN');
+ stringify(Infinity).should.equal('Infinity');
+ stringify(-Infinity).should.equal('-Infinity');
+ });
+
+ it('floats and ints', function() {
+ stringify(1).should.equal('1');
+ stringify(1.2).should.equal('1.2');
+ stringify(1e9).should.equal('1000000000');
+ });
+ });
+
+ describe('canonicalize example', function() {
+ it('should represent the actual full result', function() {
+ var expected = {
+ str: 'string',
+ int: 90,
+ float: 9.99,
+ boolean: false,
+ nil: null,
+ undef: undefined,
+ regex: /^[a-z|A-Z]/,
+ date: new Date(0),
+ func: function() {},
+ infi: Infinity,
+ nan: NaN,
+ zero: -0,
+ buffer: new Buffer([0x01, 0x02]),
+ array: [1,2,3],
+ empArr: [],
+ matrix: [[1], [2,3,4] ],
+ object: { a: 1, b: 2 },
+ canObj: { a: { b: 1, c: 2 }, b: {} },
+ empObj: {}
+ };
+ expected.circular = expected; // Make `Circular` situation
+ var actual = ['{'
+ , ' "array": ['
+ , ' 1'
+ , ' 2'
+ , ' 3'
+ , ' ]'
+ , ' "boolean": false'
+ , ' "buffer": [Buffer: ['
+ , ' 1'
+ , ' 2'
+ , ' ]]'
+ , ' "canObj": {'
+ , ' "a": {'
+ , ' "b": 1'
+ , ' "c": 2'
+ , ' }'
+ , ' "b": {}'
+ , ' }'
+ , ' "circular": [Circular]'
+ , ' "date": [Date: 1970-01-01T00:00:00.000Z]'
+ , ' "empArr": []'
+ , ' "empObj": {}'
+ , ' "float": 9.99'
+ , ' "func": [Function]'
+ , ' "infi": Infinity'
+ , ' "int": 90'
+ , ' "matrix": ['
+ , ' ['
+ , ' 1'
+ , ' ]'
+ , ' ['
+ , ' 2'
+ , ' 3'
+ , ' 4'
+ , ' ]'
+ , ' ]'
+ , ' "nan": NaN'
+ , ' "nil": [null]'
+ , ' "object": {'
+ , ' "a": 1'
+ , ' "b": 2'
+ , ' }'
+ , ' "regex": /^[a-z|A-Z]/'
+ , ' "str": "string"'
+ , ' "undef": [undefined]'
+ , ' "zero": -0'
+ , '}'].join('\n');
+ stringify(expected).should.equal(actual);
+ });
+ });
+
+ it('should canonicalize the object', function(){
var travis = { name: 'travis', age: 24 };
var travis2 = { age: 24, name: 'travis' };
- utils.stringify(travis).should.equal(utils.stringify(travis2));
+ stringify(travis).should.equal(stringify(travis2));
});
- it('should handle circular structures', function(){
+ it('should handle circular structures in objects', function(){
var travis = { name: 'travis' };
travis.whoami = travis;
- utils.stringify(travis).should.equal('{\n "name": "travis"\n "whoami": "[Circular]"\n}');
+ 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(JSON.stringify(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('[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}');
+ });
+
+ it('should handle object without an Object prototype', function () {
+ var a = Object.create(null);
+ a.foo = 1;
+
+ stringify(a).should.equal('{\n "foo": 1\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');
});
});
@@ -103,8 +365,8 @@ describe('lib/utils', function () {
.and.containEql('/tmp/mocha-utils.js')
.and.have.lengthOf(2);
existsSync('/tmp/mocha-utils-link.js').should.be.true;
- fs.rename('/tmp/mocha-utils.js', '/tmp/bob');
- existsSync('/tmp/mocha-utils-link.js').should.be.true;
+ fs.renameSync('/tmp/mocha-utils.js', '/tmp/bob');
+ existsSync('/tmp/mocha-utils-link.js').should.be.false;
utils.lookupFiles('/tmp', ['js'], false).should.eql([]);
});
diff --git a/test/browser/grep.html b/test/browser/grep.html
new file mode 100644
index 0000000..0ba47c8
--- /dev/null
+++ b/test/browser/grep.html
@@ -0,0 +1,51 @@
+<html>
+ <head>
+ <title>Mocha</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link rel="stylesheet" href="../../mocha.css" />
+ <script src="../../mocha.js"></script>
+ <script>mocha.setup('bdd')</script>
+ <script>
+ function assert(expr, msg) {
+ if (!expr) throw new Error(msg || 'failed');
+ }
+ </script>
+ <script src="grep.js"></script>
+ </head>
+ <body>
+ <div id="mocha"></div>
+ <script>
+ (function(window) {
+ var location = window.location;
+ mocha.checkLeaks();
+ var runner = mocha.run();
+ setTimeout(run, 1000);
+
+ function run() {
+ var regex = [
+ '.*', // All
+ 'm{2}', // 'mm...m'
+ '\\d', // Contains number
+ '^\\d{2}(?=\\s\\d$)', // Start with 2 numbers and end with one
+ '^@.*(?=\\(\\)$)', // Run @Array and @Function suite, but only function
+ '^@(?!.*\\)$)', // Run @Array and @Function suite, but only properties
+ '^co', // Start with 'co'
+ 'first$', // Ends with 'first'
+ '^co.*(?=second$)', // Starts with 'co', ends with 'second'
+ '^Date:\\s01\/0(?:[1-4])\/2015$', // Run all tests between '01/[01-04]/2015'
+ encodeURIComponent('^#'), // Run encoded => start with '#'
+ encodeURIComponent('^[^a-z|0-9]+$') // Run encoded => only uppercase suites(include `it` fns), e.g: CONSTANTS
+ ]
+ , qs = location.search.replace('?grep=', '')
+ , re = ~qs.indexOf('%') ? qs : decodeURIComponent(qs)
+ , grep = regex[regex.indexOf(re) + 1];
+
+ return grep
+ ? location.search = 'grep=' + grep
+ : false;
+ }
+ })(window);
+ </script>
+ </body>
+</html>
diff --git a/test/browser/grep.js b/test/browser/grep.js
new file mode 100644
index 0000000..9531b87
--- /dev/null
+++ b/test/browser/grep.js
@@ -0,0 +1,108 @@
+// numbers
+describe('21', function() {
+ it('1', function() {
+ assert(true);
+ });
+ it('2', function() {
+ assert(true);
+ });
+});
+// symbols
+describe('@Array', function() {
+ it('.pop()', function() {
+ assert(true);
+ });
+ it('.push()', function() {
+ assert(true);
+ });
+ it('.length', function() {
+ assert(true);
+ });
+});
+
+describe('@Function', function() {
+ it('.call()', function() {
+ assert(true);
+ });
+ it('.apply()', function() {
+ assert(true);
+ });
+ it('.length', function() {
+ assert(true);
+ });
+ it('.name', function() {
+ assert(true);
+ });
+ it('.prototype', function() {
+ assert(true);
+ });
+});
+
+//url with hashtags
+describe('#Services',function() {
+ describe('#http', function() {
+ it('.createClient()', function() {
+ assert(true);
+ });
+ it('.Server()', function() {
+ assert(true);
+ });
+ });
+ describe('#crypto', function() {
+ it('.randomBytes()', function() {
+ assert(true);
+ });
+ it('.Hmac()', function() {
+ assert(true);
+ });
+ });
+});
+
+// Uppercase
+describe('CONSTANTS', function() {
+ it('.STATUS_CODES', function() {
+ assert(true);
+ });
+});
+
+// Dates
+describe('Date:', function() {
+ it('01/02/2015', function() {
+ assert(true);
+ });
+ it('01/03/2015', function() {
+ assert(true);
+ });
+ it('01/06/2015', function() {
+ assert(true);
+ });
+});
+
+// etc..
+describe('booking/summary', function() {
+ it('should be run last', function() {
+ assert(true);
+ });
+});
+
+describe('component/booking/summary', function() {
+ it('should be run second', function() {
+ assert(true);
+ });
+});
+
+describe('component/booking/intro', function() {
+ it('should be run first', function() {
+ assert(true);
+ });
+});
+
+describe('contains numbers', function() {
+ it('should run if the number 92 matching', function() {
+ assert(true);
+ });
+
+ it('should run if the number 8 matching', function() {
+ assert(true);
+ });
+});
\ No newline at end of file
diff --git a/test/browser/large.js b/test/browser/large.js
index 1250aba..56757ea 100644
--- a/test/browser/large.js
+++ b/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/test/browser/stack-trace.html b/test/browser/stack-trace.html
new file mode 100644
index 0000000..0f267da
--- /dev/null
+++ b/test/browser/stack-trace.html
@@ -0,0 +1,24 @@
+<html>
+<head>
+ <title>Mocha</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link rel="stylesheet" href="../../mocha.css" />
+ <script src="../../mocha.js"></script>
+ <script>mocha.setup('bdd')</script>
+ <script>
+ function assert(expr, err) {
+ if (!expr) throw err;
+ }
+ </script>
+ <script src="stack-trace.js"></script>
+ <script>
+ onload = function() {
+ mocha.run();
+ };
+ </script>
+</head>
+<body>
+<div id="mocha"></div>
+</body>
+</html>
diff --git a/test/browser/stack-trace.js b/test/browser/stack-trace.js
new file mode 100644
index 0000000..b39944d
--- /dev/null
+++ b/test/browser/stack-trace.js
@@ -0,0 +1,20 @@
+'use strict';
+describe('Stack trace', function() {
+ it('should prettify the stack-trace', function() {
+ var err = new Error();
+ // We do this fake stack-trace because we under development,
+ // and our root isn't `node_modules`, `bower` or `components`
+ err.stack = ['Error: failed'
+ , 'at assert (stack-trace.html:11:30)'
+ , 'at Context.<anonymous> (stack-trace.js:5:5)'
+ , 'at callFn (http://localhost:63342/node_modules/mocha.js:4546:21)'
+ , 'at Test.require.register.Runnable.run (http://localhost:63342/node_modules/mocha.js:4539:7)'
+ , 'at Runner.require.register.Runner.runTest (http://localhost:63342/node_modules/mocha.js:4958:10)'
+ , 'at http://localhost:63342/bower_components/mocha.js:5041:12'
+ , 'at next (http://localhost:63342/bower_components/mocha.js:4883:14)'
+ , 'at http://localhost:63342/bower_components/mocha.js:4893:7'
+ , 'at next (http://localhost:63342/bower_components/mocha.js:4828:23)'
+ , 'at http://localhost:63342/bower_components/mocha.js:4860:5'].join('\n');
+ assert(false, err);
+ });
+});
\ No newline at end of file
diff --git a/test/color.js b/test/color.js
new file mode 100644
index 0000000..8c7167b
--- /dev/null
+++ b/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/test/grep.js b/test/grep.js
index b4be371..633aab4 100644
--- a/test/grep.js
+++ b/test/grep.js
@@ -1,16 +1,22 @@
-
var Mocha = require('../');
describe('Mocha', function(){
describe('"grep" option', function(){
it('should add a RegExp to the mocha.options object', function(){
- var mocha = new Mocha({ grep: /foo/ });
- mocha.options.grep.toString().should.equal('/foo/');
+ var mocha = new Mocha({ grep: /foo.*/ });
+ mocha.options.grep.toString().should.equal('/foo.*/');
})
- it('should convert grep string to a RegExp', function(){
- var mocha = new Mocha({ grep: 'foo' });
- mocha.options.grep.toString().should.equal('/foo/');
+ it('should convert string to a RegExp', function(){
+ var mocha = new Mocha({ grep: 'foo.*' });
+ mocha.options.grep.toString().should.equal('/foo.*/');
+ })
+ })
+
+ describe('"fgrep" option', function(){
+ it('should escape and convert string to a RegExp', function(){
+ var mocha = new Mocha({ fgrep: 'foo.*' });
+ mocha.options.grep.toString().should.equal('/foo\\.\\*/');
})
})
diff --git a/test/hook.async.js b/test/hook.async.js
index fd62932..ae6e642 100644
--- a/test/hook.async.js
+++ b/test/hook.async.js
@@ -1,4 +1,3 @@
-
describe('async', function(){
var calls = [];
diff --git a/test/hook.err.js b/test/hook.err.js
index f28ecdd..d7e6c2e 100644
--- a/test/hook.err.js
+++ b/test/hook.err.js
@@ -195,7 +195,7 @@ describe('hook error handling', function(){
after(function(){
calls.push("1.2 after");
});
- });
+ });
afterEach(function() {
calls.push('1 after each')
@@ -244,7 +244,7 @@ describe('hook error handling', function(){
after(function(){
calls.push("2.2 after");
});
- });
+ });
afterEach(function() {
calls.push('2 after each')
@@ -293,4 +293,4 @@ describe('hook error handling', function(){
});
})
-})
\ No newline at end of file
+})
diff --git a/test/hook.sync.js b/test/hook.sync.js
index c446c6a..1d40f5d 100644
--- a/test/hook.sync.js
+++ b/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/test/hook.sync.nested.js b/test/hook.sync.nested.js
index 94c00da..b87c222 100644
--- a/test/hook.sync.nested.js
+++ b/test/hook.sync.nested.js
@@ -1,4 +1,3 @@
-
describe('serial', function(){
describe('nested', function(){
var calls = [];
diff --git a/test/hook.timeout.js b/test/hook.timeout.js
index 5b158e2..155c1e9 100644
--- a/test/hook.timeout.js
+++ b/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/test/http.meta.2.js b/test/http.meta.2.js
index bcc6b6b..fe9662b 100644
--- a/test/http.meta.2.js
+++ b/test/http.meta.2.js
@@ -1,6 +1,7 @@
-
var http = require('http');
+var PORT = 8899;
+
var server = http.createServer(function(req, res){
var accept = req.headers.accept || ''
, json = ~accept.indexOf('json');
@@ -19,15 +20,13 @@ var server = http.createServer(function(req, res){
}
})
-server.listen(8899);
-
function get(url) {
var fields
, expected
, header = {};
function request(done) {
- http.get({ path: url, port: 8899, headers: header }, function(res){
+ http.get({ path: url, port: PORT, headers: header }, function(res){
var buf = '';
res.should.have.property('statusCode', 200);
res.setEncoding('utf8');
@@ -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);
@@ -67,6 +67,15 @@ function get(url) {
}
describe('http server', function(){
+
+ before(function(done) {
+ server.listen(PORT, done);
+ });
+
+ after(function() {
+ server.close();
+ });
+
get('/')
.should
.respond('hello')
@@ -79,4 +88,4 @@ describe('http server', function(){
.set('Accept', 'application/json')
.should
.respond('["tobi","loki","jane"]')
-})
\ No newline at end of file
+})
diff --git a/test/http.meta.js b/test/http.meta.js
index 9ae90d8..5d1fb67 100644
--- a/test/http.meta.js
+++ b/test/http.meta.js
@@ -1,6 +1,7 @@
-
var http = require('http');
+var PORT = 8889;
+
var server = http.createServer(function(req, res){
var accept = req.headers.accept || ''
, json = ~accept.indexOf('json');
@@ -17,13 +18,12 @@ var server = http.createServer(function(req, res){
}
break;
}
-})
+});
-server.listen(8889);
function get(url, body, header) {
return function(done){
- http.get({ path: url, port: 8889, headers: header }, function(res){
+ http.get({ path: url, port: PORT, headers: header || {}}, function(res){
var buf = '';
res.should.have.property('statusCode', 200);
res.setEncoding('utf8');
@@ -36,8 +36,17 @@ function get(url, body, header) {
}
}
-describe('http requests', function(){
- describe('GET /', function(){
+describe('http requests', function () {
+
+ before(function(done) {
+ server.listen(PORT, done);
+ });
+
+ after(function() {
+ server.close();
+ });
+
+ describe('GET /', function () {
it('should respond with hello',
get('/', 'hello'))
})
@@ -49,4 +58,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/test/integration/diffs.js b/test/integration/diffs.js
new file mode 100644
index 0000000..d8aebba
--- /dev/null
+++ b/test/integration/diffs.js
@@ -0,0 +1,45 @@
+var assert = require('assert');
+var helpers = require('./helpers');
+var run = helpers.runMocha;
+var fs = require('fs');
+var getDiffs = helpers.getDiffs;
+
+function getExpectedOutput() {
+ var output = fs.readFileSync('test/integration/fixtures/diffs/output', 'UTF8');
+
+ // Diffs are delimited in file by "// DIFF"
+ return output.split(/\s*\/\/ DIFF/).slice(1).map(function(diff) {
+ return diff.split('\n').filter(Boolean).join('\n');
+ });
+}
+
+describe('diffs', function() {
+ var diffs, expected;
+ this.timeout(1000);
+
+ before(function(done) {
+ run('diffs/diffs.js', ['-C'], function(err, res) {
+ expected = getExpectedOutput();
+ diffs = getDiffs(res.output);
+ done(err);
+ });
+ });
+
+ [
+ 'should display a diff for small strings',
+ 'should display a diff of canonicalized objects',
+ 'should display a diff for medium strings',
+ 'should display a diff for entire object dumps',
+ 'should display a diff for multi-line strings',
+ 'should display a diff for entire object dumps',
+ 'should display a full-comparison with escaped special characters',
+ 'should display a word diff for large strings',
+ 'should work with objects',
+ 'should show value diffs and not be affected by commas',
+ 'should display diff by data and not like an objects'
+ ].forEach(function(title, i) {
+ it(title, function() {
+ assert.equal(diffs[i], expected[i]);
+ });
+ });
+});
diff --git a/test/integration/fixtures/cascade.js b/test/integration/fixtures/cascade.js
new file mode 100644
index 0000000..10b1c37
--- /dev/null
+++ b/test/integration/fixtures/cascade.js
@@ -0,0 +1,57 @@
+describe('one', function() {
+ before(function() {
+ console.log('before one');
+ });
+
+ after(function() {
+ console.log('after one');
+ });
+
+ beforeEach(function() {
+ console.log(' before each one');
+ });
+
+ afterEach(function() {
+ console.log(' after each one');
+ });
+
+ describe('two', function() {
+ before(function() {
+ console.log(' before two');
+ });
+
+ after(function() {
+ console.log(' after two');
+ });
+
+ beforeEach(function() {
+ console.log(' before each two');
+ });
+
+ afterEach(function() {
+ console.log(' after each two');
+ });
+
+ describe('three', function() {
+ before(function() {
+ console.log(' before three');
+ });
+
+ after(function() {
+ console.log(' after three');
+ });
+
+ beforeEach(function() {
+ console.log(' before each three');
+ });
+
+ afterEach(function() {
+ console.log(' after each three');
+ });
+
+ it('should three', function() {
+ console.log(' TEST three');
+ });
+ });
+ });
+});
diff --git a/test/acceptance/fixtures/css.in b/test/integration/fixtures/diffs/diffs.css.in
similarity index 98%
rename from test/acceptance/fixtures/css.in
rename to test/integration/fixtures/diffs/diffs.css.in
index 29fb274..09a3ca5 100644
--- a/test/acceptance/fixtures/css.in
+++ b/test/integration/fixtures/diffs/diffs.css.in
@@ -6,4 +6,4 @@ body {
a {
color: blue
-}
\ No newline at end of file
+}
diff --git a/test/acceptance/fixtures/css.out b/test/integration/fixtures/diffs/diffs.css.out
similarity index 98%
rename from test/acceptance/fixtures/css.out
rename to test/integration/fixtures/diffs/diffs.css.out
index 643692a..53b3ec9 100644
--- a/test/acceptance/fixtures/css.out
+++ b/test/integration/fixtures/diffs/diffs.css.out
@@ -10,4 +10,4 @@ a {
foo {
bar: 'baz';
-}
\ No newline at end of file
+}
diff --git a/test/integration/fixtures/diffs/diffs.js b/test/integration/fixtures/diffs/diffs.js
new file mode 100644
index 0000000..cf538fd
--- /dev/null
+++ b/test/integration/fixtures/diffs/diffs.js
@@ -0,0 +1,84 @@
+var fs = require('fs');
+var assert = require('assert');
+var cssin = fs.readFileSync('test/integration/fixtures/diffs/diffs.css.in', 'ascii');
+var cssout = fs.readFileSync('test/integration/fixtures/diffs/diffs.css.out', 'ascii');
+
+describe('diffs', function() {
+ var actual, expected;
+
+ it('should display a diff for small strings', function() {
+ actual = 'foo rar baz';
+ expected = 'foo bar baz';
+ actual.should.equal(expected);
+ });
+
+ it('should display a diff of canonicalized objects', function() {
+ actual = { name: 'travis j', age: 23 };
+ expected = { age: 23, name: 'travis' };
+ actual.should.equal(expected);
+ });
+
+ it('should display a diff for medium strings', function() {
+ actual = 'foo bar baz\nfoo rar baz\nfoo bar raz';
+ expected = 'foo bar baz\nfoo bar baz\nfoo bar baz';
+ actual.should.equal(expected);
+ });
+
+ it('should display a diff for entire object dumps', function() {
+ actual = { name: 'joel', age: 30, address: {city: 'new york', country: 'usa' }};
+ expected = { name: 'joe', age: 30, address: {city: 'new york', country: 'us' }};
+ actual.should.equal(expected);
+ });
+
+ it('should display a diff for multi-line strings', function() {
+ actual = 'one two three\nfour zzzz six\nseven eight nine';
+ expected = 'one two three\nfour five six\nseven eight nine';
+ actual.should.equal(expected);
+ });
+
+ it('should display a diff for entire object dumps', function() {
+ actual = { name: 'joel', age: 30, address: {city: 'new york', country: 'usa' }};
+ expected = { name: 'joe', age: 30, address: {city: 'new york', country: 'us' }}
+ actual.should.equal(expected);
+ });
+
+ it('should display a full-comparison with escaped special characters', function() {
+ actual = 'one\ttab\ntwo\t\t\ttabs';
+ expected = 'one\ttab\ntwo\t\ttabs';
+ actual.should.equal(expected);
+ });
+
+ it('should display a word diff for large strings', function() {
+ cssin.should.equal(cssout);
+ });
+
+ it('should work with objects', function() {
+ actual = {
+ name: 'tobi',
+ species: 'ferret',
+ color: 'white',
+ age: 2
+ };
+
+ expected = {
+ name: 'loki',
+ species: 'ferret',
+ color: 'brown',
+ age: 2
+ };
+
+ actual.should.eql(expected);
+ });
+
+ it('should show value diffs and not be affected by commas', function() {
+ actual = { a: 123 };
+ expected = { a: 123, b: 456 };
+ actual.should.equal(expected);
+ });
+
+ it('should display diff by data and not like an objects', function() {
+ actual = new Buffer([0x01]);
+ expected = new Buffer([0x02]);
+ actual.should.equal(expected);
+ });
+});
diff --git a/test/integration/fixtures/diffs/output b/test/integration/fixtures/diffs/output
new file mode 100644
index 0000000..bf56a96
--- /dev/null
+++ b/test/integration/fixtures/diffs/output
@@ -0,0 +1,91 @@
+// DIFF
+ -foo rar baz
+ +foo bar baz
+
+// DIFF
+ {
+ "age": 23
+ - "name": "travis j"
+ + "name": "travis"
+ }
+
+// DIFF
+ foo bar baz
+ -foo rar baz
+ -foo bar raz
+ +foo bar baz
+ +foo bar baz
+
+// DIFF
+ {
+ "address": {
+ "city": "new york"
+ - "country": "usa"
+ + "country": "us"
+ }
+ "age": 30
+ - "name": "joel"
+ + "name": "joe"
+ }
+
+// DIFF
+ one two three
+ -four zzzz six
+ +four five six
+ seven eight nine
+
+// DIFF
+ {
+ "address": {
+ "city": "new york"
+ - "country": "usa"
+ + "country": "us"
+ }
+ "age": 30
+ - "name": "joel"
+ + "name": "joe"
+ }
+
+// DIFF
+ one tab
+ -two tabs
+ +two tabs
+
+// DIFF
+ body {
+ font: "Helvetica Neue", Helvetica, arial, sans-serif;
+ background: black;
+ - color: white;
+ + color: #fff;
+ }
+
+ a {
+ - color: blue
+ + color: blue;
+ }
+ +
+ +foo {
+ + bar: 'baz';
+ +}
+
+// DIFF
+ {
+ "age": 2
+ - "color": "white"
+ - "name": "tobi"
+ + "color": "brown"
+ + "name": "loki"
+ "species": "ferret"
+ }
+
+// DIFF
+ {
+ "a": 123
+ + "b": 456
+ }
+
+// DIFF
+ [
+ - 1
+ + 2
+ ]
diff --git a/test/integration/fixtures/multiple.done.js b/test/integration/fixtures/multiple.done.js
new file mode 100644
index 0000000..63a7040
--- /dev/null
+++ b/test/integration/fixtures/multiple.done.js
@@ -0,0 +1,18 @@
+// The suite below should result in an additional error, but does
+// not. Uncomment once this bug is resolved.
+
+// describe('suite', function() {
+// beforeEach(function(done) {
+// done();
+// done();
+// });
+
+// it('test', function() {});
+// });
+
+it('should fail in a test-case', function(done) {
+ process.nextTick(function(){
+ done();
+ done();
+ });
+});
diff --git a/test/integration/fixtures/options/async-only.async.js b/test/integration/fixtures/options/async-only.async.js
new file mode 100644
index 0000000..5387d16
--- /dev/null
+++ b/test/integration/fixtures/options/async-only.async.js
@@ -0,0 +1,3 @@
+it('should pass', function(done){
+ done();
+});
diff --git a/test/integration/fixtures/options/async-only.sync.js b/test/integration/fixtures/options/async-only.sync.js
new file mode 100644
index 0000000..d0dd9fa
--- /dev/null
+++ b/test/integration/fixtures/options/async-only.sync.js
@@ -0,0 +1 @@
+it('throws an error', function() {});
diff --git a/test/integration/fixtures/options/bail.js b/test/integration/fixtures/options/bail.js
new file mode 100644
index 0000000..bb8ad13
--- /dev/null
+++ b/test/integration/fixtures/options/bail.js
@@ -0,0 +1,25 @@
+describe('suite1', function() {
+ it('should display this spec', function() {});
+
+ it('should only display this error', function(done) {
+ throw new Error('this should be displayed');
+ });
+
+ it('should not display this error', function(done) {
+ throw new Error('this should not be displayed');
+ });
+});
+
+describe('suite2', function() {
+ // TODO: When uncommented, the hook below is ran and throws an exception
+ // despite the previous failure with the bail flag. This is a bug. Uncomment
+ // once resolved
+
+ // before(function(done) {
+ // throw new Error('this hook should not be displayed');
+ // });
+
+ it('should not display this error', function(done) {
+ throw new Error('this should not be displayed');
+ });
+});
diff --git a/test/integration/fixtures/options/delay.js b/test/integration/fixtures/options/delay.js
new file mode 100644
index 0000000..32b8f99
--- /dev/null
+++ b/test/integration/fixtures/options/delay.js
@@ -0,0 +1,19 @@
+var assert = require('assert');
+var delay = 500;
+var start = new Date().getTime();
+
+setTimeout(function() {
+ describe('delayed execution', function() {
+ it('should have waited ' + delay + 'ms to run this suite', function() {
+ assert(new Date().getTime() - delay >= start);
+ });
+
+ it('should have no effect if attempted twice in the same suite', function() {
+ assert(true);
+ run();
+ assert(true);
+ });
+ });
+
+ run();
+}, delay);
diff --git a/test/integration/fixtures/options/grep.js b/test/integration/fixtures/options/grep.js
new file mode 100644
index 0000000..5e163f5
--- /dev/null
+++ b/test/integration/fixtures/options/grep.js
@@ -0,0 +1,12 @@
+describe('grep', function() {
+ describe('match', function() {
+ it('should run', function(){});
+ it('should also run', function() {});
+ });
+
+ describe('fail', function(){
+ it('should not be ran', function() {
+ throw new Error('Spec should not run');
+ });
+ });
+});
diff --git a/test/acceptance/sort/alpha.js b/test/integration/fixtures/options/sort.alpha.js
similarity index 97%
rename from test/acceptance/sort/alpha.js
rename to test/integration/fixtures/options/sort.alpha.js
index 365f39c..7a53029 100644
--- a/test/acceptance/sort/alpha.js
+++ b/test/integration/fixtures/options/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/test/acceptance/sort/beta.js b/test/integration/fixtures/options/sort.beta.js
similarity index 96%
rename from test/acceptance/sort/beta.js
rename to test/integration/fixtures/options/sort.beta.js
index 3de3e0c..0951f49 100644
--- a/test/acceptance/sort/beta.js
+++ b/test/integration/fixtures/options/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/test/integration/fixtures/pending/skip.sync.before.js b/test/integration/fixtures/pending/skip.sync.before.js
new file mode 100644
index 0000000..35152e2
--- /dev/null
+++ b/test/integration/fixtures/pending/skip.sync.before.js
@@ -0,0 +1,13 @@
+describe('skip in before', function() {
+ before(function() {
+ this.skip();
+ });
+
+ it('should never run this test', function() {
+ throw new Error('never thrown');
+ });
+
+ it('should never run this test', function() {
+ throw new Error('never thrown');
+ });
+});
diff --git a/test/integration/fixtures/pending/skip.sync.beforeEach.js b/test/integration/fixtures/pending/skip.sync.beforeEach.js
new file mode 100644
index 0000000..8d1c442
--- /dev/null
+++ b/test/integration/fixtures/pending/skip.sync.beforeEach.js
@@ -0,0 +1,13 @@
+describe('skip in beforeEach', function() {
+ beforeEach(function() {
+ this.skip();
+ });
+
+ it('should never run this test', function() {
+ throw new Error('never thrown');
+ });
+
+ it('should never run this test', function() {
+ throw new Error('never thrown');
+ });
+});
diff --git a/test/integration/fixtures/pending/skip.sync.spec.js b/test/integration/fixtures/pending/skip.sync.spec.js
new file mode 100644
index 0000000..e2bbb73
--- /dev/null
+++ b/test/integration/fixtures/pending/skip.sync.spec.js
@@ -0,0 +1,10 @@
+describe('skip in test', function() {
+ it('should skip immediately', function() {
+ this.skip();
+ throw new Error('never thrown');
+ });
+
+ it('should run other tests in the suite', function() {
+ // Do nothing
+ });
+});
diff --git a/test/integration/fixtures/pending/spec.js b/test/integration/fixtures/pending/spec.js
new file mode 100644
index 0000000..084dd33
--- /dev/null
+++ b/test/integration/fixtures/pending/spec.js
@@ -0,0 +1,3 @@
+describe('suite', function() {
+ it('pending spec');
+});
diff --git a/test/integration/fixtures/regression/issue-1327.js b/test/integration/fixtures/regression/issue-1327.js
new file mode 100644
index 0000000..43d5553
--- /dev/null
+++ b/test/integration/fixtures/regression/issue-1327.js
@@ -0,0 +1,15 @@
+it('test 1', function() {
+ console.log('testbody1');
+ process.nextTick(function() {
+ throw 'Too bad';
+ });
+});
+
+it('test 2', function() {
+ console.log('testbody2');
+});
+
+it('test 3', function() {
+ console.log('testbody3');
+ throw new Error('OUCH');
+});
diff --git a/test/integration/fixtures/timeout.js b/test/integration/fixtures/timeout.js
new file mode 100644
index 0000000..d8c99b2
--- /dev/null
+++ b/test/integration/fixtures/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());
+ }
+});
diff --git a/test/integration/fixtures/uncaught.hook.js b/test/integration/fixtures/uncaught.hook.js
new file mode 100644
index 0000000..9adcb3f
--- /dev/null
+++ b/test/integration/fixtures/uncaught.hook.js
@@ -0,0 +1,15 @@
+describe('uncaught', function() {
+ beforeEach(function(done) {
+ process.nextTick(function() {
+ throw new Error('oh noes');
+ done();
+ });
+ });
+
+ it('test', function(done) {
+ process.nextTick(function() {
+ throw new Error("I'm uncaught!");
+ done();
+ });
+ });
+});
diff --git a/test/integration/fixtures/uncaught.js b/test/integration/fixtures/uncaught.js
new file mode 100644
index 0000000..054d1d8
--- /dev/null
+++ b/test/integration/fixtures/uncaught.js
@@ -0,0 +1,26 @@
+'use strict';
+
+/**
+ * This file should only generate one failure per spec despite the fact that
+ * Mocha is capable of detecting two distinct exceptions during test execution.
+ */
+
+it('fails exactly once when a global error is thrown first', function(done) {
+ setTimeout(function() {
+ throw new Error('global error');
+
+ setTimeout(function() {
+ done(new Error('test error'));
+ }, 0);
+ }, 0);
+});
+
+it('fails exactly once when a global error is thrown second', function(done) {
+ setTimeout(function() {
+ done(new Error('test error'));
+ }, 0);
+
+ setTimeout(function() {
+ throw new Error('global error');
+ }, 0);
+});
diff --git a/test/integration/helpers.js b/test/integration/helpers.js
new file mode 100644
index 0000000..eea8b18
--- /dev/null
+++ b/test/integration/helpers.js
@@ -0,0 +1,142 @@
+var spawn = require('child_process').spawn;
+var path = require('path');
+
+module.exports = {
+ /**
+ * Invokes the mocha binary for the given fixture with color output disabled.
+ * Accepts an array of additional command line args to pass. The callback is
+ * invoked with a summary of the run, in addition to its output. The summary
+ * includes the number of passing, pending, and failing tests, as well as the
+ * exit code. Useful for testing different reporters.
+ *
+ * Example response:
+ * {
+ * pending: 0,
+ * passing: 0,
+ * failing: 1,
+ * code: 1,
+ * output: '...'
+ * }
+ *
+ * @param {string} fixturePath
+ * @param {array} args
+ * @param {function} fn
+ */
+ runMocha: function(fixturePath, args, fn) {
+ var path;
+
+ path = resolveFixturePath(fixturePath);
+ args = args || [];
+
+ invokeMocha(args.concat(['-C', path]), function(err, res) {
+ if (err) return fn(err);
+
+ fn(null, getSummary(res));
+ });
+ },
+
+ /**
+ * Invokes the mocha binary for the given fixture using the JSON reporter,
+ * returning the parsed output, as well as exit code.
+ *
+ * @param {string} fixturePath
+ * @param {array} args
+ * @param {function} fn
+ */
+ runMochaJSON: function(fixturePath, args, fn) {
+ var path;
+
+ path = resolveFixturePath(fixturePath);
+ args = args || [];
+
+ invokeMocha(args.concat(['--reporter', 'json', path]), function(err, res) {
+ if (err) return fn(err);
+
+ try {
+ var result = JSON.parse(res.output);
+ result.code = res.code;
+ } catch (err) {
+ return fn(err);
+ }
+
+ fn(null, result);
+ });
+ },
+
+ /**
+ * Returns an array of diffs corresponding to exceptions thrown from specs,
+ * given the plaintext output (-C) of a mocha run.
+ *
+ * @param {string} output
+ * returns {string[]}
+ */
+ getDiffs: function(output) {
+ var diffs, i, inDiff, inStackTrace;
+
+ diffs = [];
+ output.split('\n').forEach(function(line) {
+ if (line.match(/^ \d+\)/)) {
+ // New spec, e.g. "1) spec title"
+ diffs.push([]);
+ i = diffs.length - 1;
+ inStackTrace = false;
+ inDiff = false;
+ } else if (!diffs.length || inStackTrace) {
+ // Haven't encountered a spec yet
+ // or we're in the middle of a stack trace
+ return;
+ } else if (line.indexOf('+ expected - actual') !== -1) {
+ inDiff = true;
+ } else if (line.match(/at Context/)) {
+ // At the start of a stack trace
+ inStackTrace = true;
+ inDiff = false;
+ } else if (inDiff) {
+ diffs[i].push(line);
+ }
+ });
+
+ // Ignore empty lines before/after diff
+ return diffs.map(function(diff) {
+ return diff.slice(1, -1).join('\n');
+ });
+ }
+};
+
+function invokeMocha(args, fn) {
+ var output, mocha, listener;
+
+ output = '';
+ mocha = spawn('./bin/mocha', args);
+
+ listener = function(data) {
+ output += data;
+ };
+
+ mocha.stdout.on('data', listener);
+ mocha.stderr.on('data', listener);
+ mocha.on('error', fn);
+
+ mocha.on('close', function(code) {
+ fn(null, {
+ output: output.split('\n').join('\n'),
+ code: code
+ });
+ });
+}
+
+function resolveFixturePath(fixture) {
+ return path.join('./test/integration/fixtures', fixture);
+}
+
+function getSummary(res) {
+ return ['passing', 'pending', 'failing'].reduce(function(summary, type) {
+ var pattern, match;
+
+ pattern = new RegExp(' (\\d+) ' + type + '\\s');
+ match = pattern.exec(res.output);
+ summary[type] = (match) ? parseInt(match, 10) : 0;
+
+ return summary;
+ }, res);
+}
diff --git a/test/integration/hooks.js b/test/integration/hooks.js
new file mode 100644
index 0000000..4236c7f
--- /dev/null
+++ b/test/integration/hooks.js
@@ -0,0 +1,44 @@
+var assert = require('assert');
+var run = require('./helpers').runMocha;
+var args = [];
+
+describe('hooks', function() {
+ this.timeout(1000);
+
+ it('are ran in correct order', function(done) {
+ run('cascade.js', args, function(err, res) {
+ var lines, expected;
+
+ assert(!err);
+
+ lines = res.output.split(/[\n․]+/).map(function(line) {
+ return line.trim();
+ }).filter(function(line) {
+ return line.length;
+ }).slice(0, -1);
+
+ expected = [
+ 'before one',
+ 'before two',
+ 'before three',
+ 'before each one',
+ 'before each two',
+ 'before each three',
+ 'TEST three',
+ 'after each three',
+ 'after each two',
+ 'after each one',
+ 'after three',
+ 'after two',
+ 'after one'
+ ];
+
+ expected.forEach(function(line, i) {
+ assert.equal(lines[i], line);
+ });
+
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+});
diff --git a/test/integration/multiple.done.js b/test/integration/multiple.done.js
new file mode 100644
index 0000000..8f9a3cd
--- /dev/null
+++ b/test/integration/multiple.done.js
@@ -0,0 +1,28 @@
+var assert = require('assert');
+var run = require('./helpers').runMochaJSON;
+var args = [];
+
+describe('multiple calls to done()', function() {
+ var res;
+
+ this.timeout(1000);
+
+ before(function(done) {
+ run('multiple.done.js', args, function(err, result) {
+ res = result;
+ done(err);
+ });
+ });
+
+ it('results in failures', function() {
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 1);
+ assert.equal(res.stats.failures, 1);
+ assert.equal(res.code, 1);
+ });
+
+ it('throws a descriptive error', function() {
+ assert.equal(res.failures[0].err.message,
+ 'done() called multiple times');
+ });
+});
diff --git a/test/integration/options.js b/test/integration/options.js
new file mode 100644
index 0000000..db37109
--- /dev/null
+++ b/test/integration/options.js
@@ -0,0 +1,140 @@
+var assert = require('assert');
+var run = require('./helpers').runMochaJSON;
+var args = [];
+
+describe('options', function() {
+ this.timeout(2000);
+
+ describe('--async-only', function() {
+
+ before(function() {
+ args = ['--async-only'];
+ });
+
+ it('should fail synchronous specs', function(done) {
+ run('options/async-only.sync.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 0);
+ assert.equal(res.stats.failures, 1);
+
+ assert.equal(res.failures[0].title, 'throws an error');
+ assert.equal(res.code, 1);
+ done();
+ });
+ });
+
+ it('should allow asynchronous specs', function(done) {
+ run('options/async-only.async.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 1);
+ assert.equal(res.stats.failures, 0);
+
+ assert.equal(res.passes[0].title, 'should pass');
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+ });
+
+ describe('--bail', function() {
+ before(function() {
+ args = ['--bail'];
+ });
+
+ it('should stop after the first error', function(done) {
+ run('options/bail.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 1);
+ assert.equal(res.stats.failures, 1);
+
+ assert.equal(res.passes[0].title, 'should display this spec');
+ assert.equal(res.failures[0].title, 'should only display this error');
+ assert.equal(res.code, 1);
+ done();
+ });
+ });
+ });
+
+ describe('--sort', function() {
+ before(function() {
+ args = ['--sort'];
+ });
+
+ it('should sort tests in alphabetical order', function(done) {
+ run('options/sort*', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 2);
+ assert.equal(res.stats.failures, 0);
+
+ assert.equal(res.passes[0].fullTitle,
+ 'alpha should be executed first');
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+ });
+
+ describe('--delay', function() {
+ before(function() {
+ args = ['--delay'];
+ });
+
+ it('should run the generated test suite', function(done) {
+ run('options/delay.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 2);
+ assert.equal(res.stats.failures, 0);
+
+ assert.equal(res.passes[0].title,
+ 'should have waited 500ms to run this suite');
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+ });
+
+ describe('--grep', function() {
+ it('runs specs matching a string', function(done) {
+ args = ['--grep', 'match'];
+ run('options/grep.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 2);
+ assert.equal(res.stats.failures, 0);
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+
+ it('runs specs matching a RegExp', function(done) {
+ args = ['--grep', '.*'];
+ run('options/grep.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 2);
+ assert.equal(res.stats.failures, 1);
+ assert.equal(res.code, 1);
+ done();
+ });
+ });
+
+ describe('with --invert', function() {
+ it('runs specs that do not match the pattern', function(done) {
+ args = ['--grep', 'fail', '--invert'];
+ run('options/grep.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 2);
+ assert.equal(res.stats.failures, 0);
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/integration/pending.js b/test/integration/pending.js
new file mode 100644
index 0000000..01ebbdf
--- /dev/null
+++ b/test/integration/pending.js
@@ -0,0 +1,63 @@
+var assert = require('assert');
+var run = require('./helpers').runMochaJSON;
+var args = [];
+
+describe('pending', function() {
+ describe('pending specs', function() {
+ this.timeout(1000);
+
+ it('should be created by omitting a function', function(done) {
+ run('pending/spec.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 1);
+ assert.equal(res.stats.passes, 0);
+ assert.equal(res.stats.failures, 0);
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+ });
+
+ describe('synchronous skip()', function() {
+ this.timeout(1000);
+
+ describe('in spec', function() {
+ it('should immediately skip the spec and run all others', function(done) {
+ run('pending/skip.sync.spec.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 1);
+ assert.equal(res.stats.passes, 1);
+ assert.equal(res.stats.failures, 0);
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+ });
+
+ describe('in before', function() {
+ it('should skip all suite specs', function(done) {
+ run('pending/skip.sync.before.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 2);
+ assert.equal(res.stats.passes, 0);
+ assert.equal(res.stats.failures, 0);
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+ });
+
+ describe('in beforeEach', function() {
+ it('should skip all suite specs', function(done) {
+ run('pending/skip.sync.beforeEach.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 2);
+ assert.equal(res.stats.passes, 0);
+ assert.equal(res.stats.failures, 0);
+ assert.equal(res.code, 0);
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/integration/regression.js b/test/integration/regression.js
new file mode 100644
index 0000000..564e922
--- /dev/null
+++ b/test/integration/regression.js
@@ -0,0 +1,24 @@
+var assert = require('assert');
+var run = require('./helpers').runMocha;
+
+describe('regressions', function() {
+ this.timeout(1000);
+
+ it('issue-1327: should run all 3 specs exactly once', function(done) {
+ var args = [];
+ run('regression/issue-1327.js', args, function(err, res) {
+ var occurences = function(str) {
+ var pattern = new RegExp(str, 'g');
+ return (res.output.match(pattern) || []).length;
+ };
+
+ assert(!err);
+ assert.equal(occurences('testbody1'), 1);
+ assert.equal(occurences('testbody2'), 1);
+ assert.equal(occurences('testbody3'), 1);
+
+ assert.equal(res.code, 1);
+ done();
+ });
+ });
+});
diff --git a/test/integration/timeout.js b/test/integration/timeout.js
new file mode 100644
index 0000000..9f0985c
--- /dev/null
+++ b/test/integration/timeout.js
@@ -0,0 +1,18 @@
+var assert = require('assert');
+var run = require('./helpers').runMochaJSON;
+var args = [];
+
+describe('this.timeout()', function() {
+ this.timeout(1000);
+
+ it('is respected by sync and async suites', function(done) {
+ run('timeout.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 0);
+ assert.equal(res.stats.failures, 2);
+ assert.equal(res.code, 2);
+ done();
+ });
+ });
+});
diff --git a/test/integration/uncaught.js b/test/integration/uncaught.js
new file mode 100644
index 0000000..cddc52b
--- /dev/null
+++ b/test/integration/uncaught.js
@@ -0,0 +1,37 @@
+var assert = require('assert');
+var run = require('./helpers').runMochaJSON;
+var args = [];
+
+describe('uncaught exceptions', function() {
+ this.timeout(1000);
+
+ it('handles uncaught exceptions from hooks', function(done) {
+ run('uncaught.hook.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 0);
+ assert.equal(res.stats.failures, 1);
+
+ assert.equal(res.failures[0].fullTitle,
+ 'uncaught "before each" hook');
+ assert.equal(res.code, 1);
+ done();
+ });
+ });
+
+ it('handles uncaught exceptions from async specs', function(done) {
+ run('uncaught.js', args, function(err, res) {
+ assert(!err);
+ assert.equal(res.stats.pending, 0);
+ assert.equal(res.stats.passes, 0);
+ assert.equal(res.stats.failures, 2);
+
+ assert.equal(res.failures[0].title,
+ 'fails exactly once when a global error is thrown first');
+ assert.equal(res.failures[1].title,
+ 'fails exactly once when a global error is thrown second');
+ assert.equal(res.code, 2);
+ done();
+ });
+ });
+});
diff --git a/test/jsapi/index.js b/test/jsapi/index.js
index 5b5c169..2dbbcb0 100644
--- a/test/jsapi/index.js
+++ b/test/jsapi/index.js
@@ -1,4 +1,3 @@
-
var Mocha = require('../../')
, path = require('path');
@@ -21,7 +20,6 @@ mocha.addFile('test/hook.async.js');
mocha.addFile('test/acceptance/duration.js');
mocha.addFile('test/acceptance/fs.js');
mocha.addFile('test/acceptance/globals.js');
-mocha.addFile('test/acceptance/pending.js');
mocha.addFile('test/acceptance/timeout.js');
mocha.run(function(){
diff --git a/test/mocha.js b/test/mocha.js
new file mode 100644
index 0000000..46411fc
--- /dev/null
+++ b/test/mocha.js
@@ -0,0 +1,33 @@
+var Mocha = require('../');
+var Test = Mocha.Test;
+
+describe('Mocha', function(){
+ var blankOpts = { reporter: function(){} }; // no output
+
+ describe('.run(fn)', function(){
+ it('should not raise errors if callback was not provided', function(){
+ var mocha = new Mocha(blankOpts);
+ mocha.run();
+ })
+
+ it('should execute the callback when complete', function(done) {
+ var mocha = new Mocha(blankOpts);
+ mocha.run(function(){
+ done();
+ })
+ })
+
+ it('should execute the callback with the number of failures '+
+ 'as parameter', function(done) {
+ var mocha = new Mocha(blankOpts);
+ var failingTest = new Test('failing test', function(){
+ throw new Error('such fail');
+ });
+ mocha.suite.addTest(failingTest);
+ mocha.run(function(failures) {
+ failures.should.equal(1);
+ done();
+ });
+ })
+ })
+})
diff --git a/test/ms.js b/test/ms.js
new file mode 100644
index 0000000..1fd9740
--- /dev/null
+++ b/test/ms.js
@@ -0,0 +1,82 @@
+'use strict';
+var ms = require('../lib/ms');
+
+describe('.ms()', function() {
+ // Helpers
+ var time = {
+ minutes: function(n) { return n * 60 * 1000; },
+ hours: function (n) { return n * this.minutes(60); },
+ days: function(n) { return n * this.hours(24); },
+ years: function(n) { return n * this.days(365.25); }
+ };
+ describe('get a value that less than 1 second', function() {
+ it('should return milliseconds representation', function() {
+ ms(200).should.equal('200ms');
+ ms(30).should.equal('30ms');
+ ms(2000).should.not.equal('2000ms');
+ });
+ });
+
+ describe('seconds representation', function() {
+ it('should return short format', function() {
+ ms(2000).should.equal('2s');
+ });
+
+ it('should return long format', function() {
+ ms(2000, { long: true }).should.equal('2 seconds');
+ ms(1000, { long: true }).should.equal('1 second');
+ ms(1010, { long: true }).should.equal('1 second');
+ });
+ });
+
+ describe('minutess representation', function() {
+ it('should return short format', function() {
+ ms(time.minutes(1)).should.equal('1m');
+ });
+
+ it('should return long format', function() {
+ ms(time.minutes(1), { long: true }).should.equal('1 minute');
+ ms(time.minutes(3), { long: true }).should.equal('3 minutes');
+ });
+ });
+
+ describe('hours representation', function() {
+ it('should return short format', function() {
+ ms(time.hours(1)).should.equal('1h');
+ });
+
+ it('should return long format', function() {
+ ms(time.hours(1), { long: true }).should.equal('1 hour');
+ ms(time.hours(3), { long: true }).should.equal('3 hours');
+ });
+ });
+
+ describe('days representation', function() {
+ it('should return short format', function() {
+ ms(time.days(1)).should.equal('1d');
+ });
+
+ it('should return long format', function() {
+ ms(time.days(1), { long: true }).should.equal('1 day');
+ ms(time.days(3), { long: true }).should.equal('3 days');
+ });
+ });
+
+ describe('Getting string value', function() {
+ it('should return the milliseconds representation(Number)', function() {
+ ms('1 second').should.equal(1000);
+
+ ms('1 minute').should.equal(time.minutes(1));
+ ms('6 minutes').should.equal(time.minutes(6));
+
+ ms('1 hour').should.equal(time.hours(1));
+ ms('5 hours').should.equal(time.hours(5));
+
+ ms('1 day').should.equal(time.days(1));
+ ms('3 days').should.equal(time.days(3));
+
+ ms('1 year').should.equal(time.years(1));
+ ms('2 years').should.equal(time.years(2));
+ });
+ });
+});
diff --git a/test/regression/issue1327/case.js b/test/regression/issue1327/case.js
deleted file mode 100644
index 295ec12..0000000
--- a/test/regression/issue1327/case.js
+++ /dev/null
@@ -1,14 +0,0 @@
-var debug = require('debug')('mocha:issue1327');
-it("test 1", function() {
- debug("This runs only once.");
- process.nextTick(function() {
- throw "Too bad";
- });
-});
-it("test 2", function() {
- debug("This should run once - Previously wasn't called at all.");
-});
-it("test 3", function() {
- debug("This used to run twice.");
- throw new Error("OUCH");
-});
diff --git a/test/regression/issue1327/control.js b/test/regression/issue1327/control.js
deleted file mode 100644
index b77555d..0000000
--- a/test/regression/issue1327/control.js
+++ /dev/null
@@ -1,10 +0,0 @@
-var assert = require("assert"),
- fs = require("fs");
-
-describe("GitHub issue #1327: expected behavior of case.js", function() {
- it("should have run 3 tests", function() {
- var results = JSON.parse(fs.readFileSync(
- "test-outputs/issue1327/case-out.json"));
- results.stats.tests.should.equal(3);
- });
-});
diff --git a/test/reporters/base.js b/test/reporters/base.js
index e8fe1e6..5276979 100644
--- a/test/reporters/base.js
+++ b/test/reporters/base.js
@@ -1,68 +1,160 @@
-var Base = require('../../lib/reporters/base');
+var Base = require('../../lib/reporters/base')
+ , Assert = require('assert').AssertionError;
+
+function makeTest(err) {
+ return {
+ err: err,
+ fullTitle: function () {
+ return 'test title';
+ }
+ };
+}
describe('Base reporter', function () {
+ var stdout
+ , stdoutWrite
+ , useColors;
+
+ beforeEach(function () {
+ stdout = [];
+ stdoutWrite = process.stdout.write;
+ process.stdout.write = function (string) {
+ stdout.push(string);
+ };
+ useColors = Base.useColors;
+ Base.useColors = false;
+ });
- it('should show diffs with showDiff property set', function () {
- var err = new Error('test'),
- stderr = [],
- stderrWrite = process.stderr.write,
- errOut;
+ afterEach(function () {
+ process.stdout.write = stdoutWrite;
+ Base.useColors = useColors;
+ });
- err.actual = "a1";
- err.expected = "e1";
- err.showDiff = true;
- var test = {
- err: err,
- fullTitle: function () {
- return 'title';
- }
- };
+ describe('showDiff', function() {
+ it('should show diffs by default', function () {
+ var err = new Assert({ actual: 'foo', expected: 'bar' })
+ , errOut;
- process.stderr.write = function (string) {
- stderr.push(string);
- };
+ var test = makeTest(err);
- Base.list([test]);
+ Base.list([test]);
- process.stderr.write = stderrWrite;
+ errOut = stdout.join('\n');
+ errOut.should.match(/\- actual/);
+ errOut.should.match(/\+ expected/);
+ });
- errOut = stderr.join('\n');
+ it('should show diffs if property set to `true`', function () {
+ var err = new Assert({ actual: 'foo', expected: 'bar' })
+ , errOut;
- errOut.should.match(/test/);
- errOut.should.match(/actual/);
- errOut.should.match(/expected/);
+ err.showDiff = true;
+ var test = makeTest(err);
+
+
+ Base.list([test]);
+
+ errOut = stdout.join('\n');
+ errOut.should.match(/\- actual/);
+ errOut.should.match(/\+ expected/);
+ });
+
+ it('should not show diffs when showDiff property set to `false`', function () {
+ var err = new Assert({ actual: 'foo', expected: 'bar' })
+ , errOut;
+
+ err.showDiff = false;
+ var test = makeTest(err);
+
+ Base.list([test]);
+
+ errOut = stdout.join('\n');
+ errOut.should.not.match(/\- actual/);
+ errOut.should.not.match(/\+ expected/);
+ });
+
+ it('should not show diffs when expected is not defined', function () {
+ var err = new Error('ouch')
+ , errOut;
+
+ var test = makeTest(err);
+
+ Base.list([test]);
+ errOut = stdout.join('\n');
+ errOut.should.not.match(/\- actual/);
+ errOut.should.not.match(/\+ expected/);
+ });
+
+ });
+
+ describe('Getting two strings', function() {
+ // Fix regression V1.2.1(see: issue #1241)
+ it('should show strings diff as is', function () {
+ var err = new Error('test'),
+ errOut;
+
+ err.actual = 'foo\nbar';
+ err.expected = 'foo\nbaz';
+ err.showDiff = true;
+ var test = makeTest(err);
+
+ Base.list([test]);
+
+ errOut = stdout.join('\n');
+
+ errOut.should.not.match(/"foo\\nbar"/);
+ errOut.should.match(/foo/).and.match(/bar/);
+ errOut.should.match(/test/);
+ errOut.should.match(/actual/);
+ errOut.should.match(/expected/);
+ });
});
- it('should not show diffs when showDiff property set', function () {
+ it('should stringify objects', function () {
var err = new Error('test'),
- stderr = [],
- stderrWrite = process.stderr.write,
errOut;
- err.actual = "a1";
- err.expected = "e1";
- err.showDiff = false;
- var test = {
- err: err,
- fullTitle: function () {
- return 'title';
- }
- };
+ err.actual = {key:"a1"};
+ err.expected = {key:"e1"};
+ err.showDiff = true;
+ var test = makeTest(err);
- process.stderr.write = function (string) {
- stderr.push(string);
+ Base.list([test]);
+
+ errOut = stdout.join('\n');
+ errOut.should.match(/"key"/);
+ errOut.should.match(/test/);
+ errOut.should.match(/\- actual/);
+ errOut.should.match(/\+ expected/);
+ });
+
+ it('should remove message from stack', function () {
+ var err = {
+ message: 'Error',
+ stack: 'Error\nfoo\nbar',
+ showDiff: false
};
+ var test = makeTest(err);
Base.list([test]);
- process.stderr.write = stderrWrite;
+ var errOut = stdout.join('\n').trim();
+ errOut.should.equal('1) test title:\n Error\n foo\n bar')
+ });
- errOut = stderr.join('\n');
+ it('should not modify stack if it does not contain message', function () {
+ var err = {
+ message: 'Error',
+ stack: 'foo\nbar',
+ showDiff: false
+ };
+ var test = makeTest(err);
- errOut.should.match(/test/);
- errOut.should.not.match(/actual/);
- errOut.should.not.match(/expected/);
+ Base.list([test]);
+ var errOut = stdout.join('\n').trim();
+ errOut.should.equal('1) test title:\n Error\n foo\n bar')
});
+
});
diff --git a/test/reporters/json.js b/test/reporters/json.js
index 56173bf..e7b8955 100644
--- a/test/reporters/json.js
+++ b/test/reporters/json.js
@@ -1,4 +1,3 @@
-
var Mocha = require('../../')
, Suite = Mocha.Suite
, Runner = Mocha.Runner
@@ -14,7 +13,7 @@ describe('json reporter', function(){
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';
@@ -38,7 +37,7 @@ describe('json reporter', function(){
done();
});
- })
+ });
it('should have 1 test pending', function(done) {
var testTitle = 'json test 1';
@@ -59,4 +58,4 @@ describe('json reporter', function(){
});
})
-})
+});
diff --git a/test/reporters/nyan.js b/test/reporters/nyan.js
index 8a54458..e574808 100644
--- a/test/reporters/nyan.js
+++ b/test/reporters/nyan.js
@@ -27,4 +27,4 @@ describe('nyan face', function () {
nyanCat.face.call(nyanCat).should.equal('( - .-)');
done();
});
-})
+});
diff --git a/test/runnable.js b/test/runnable.js
index 6127b4e..2508a5f 100644
--- a/test/runnable.js
+++ b/test/runnable.js
@@ -1,5 +1,5 @@
-
var mocha = require('../')
+ , utils = mocha.utils
, Runnable = mocha.Runnable
, EventEmitter = require('events').EventEmitter;
@@ -233,9 +233,7 @@ describe('Runnable(title, fn)', function(){
});
test.run(function(err) {
- if (err !== null) {
- throw new should.AssertionError('err should be null');
- }
+ err.message.should.equal(utils.undefinedError().message);
done();
})
});
diff --git a/test/runner.js b/test/runner.js
index f5ee8cc..a2ce512 100644
--- a/test/runner.js
+++ b/test/runner.js
@@ -1,4 +1,3 @@
-
var mocha = require('../')
, Suite = mocha.Suite
, Runner = mocha.Runner
@@ -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);
@@ -206,6 +219,42 @@ describe('Runner', function(){
});
runner.fail(test, err);
})
+
+ it('should emit a helpful message when failed with a string', function(done){
+ var test = {}, err = 'string';
+ runner.on('fail', function(test, err){
+ err.message.should.equal('the string "string" was thrown, throw an Error :)');
+ done();
+ });
+ runner.fail(test, err);
+ })
+
+ it('should emit a the error when failed with an Error', function(done){
+ var test = {}, err = new Error('an error message');
+ runner.on('fail', function(test, err){
+ err.message.should.equal('an error message');
+ done();
+ });
+ runner.fail(test, err);
+ })
+
+ it('should emit a helpful message when failed with an Object', function(done){
+ var test = {}, err = { x: 1 };
+ runner.on('fail', function(test, err){
+ err.message.should.equal('the object {\n "x": 1\n} was thrown, throw an Error :)');
+ done();
+ });
+ runner.fail(test, err);
+ })
+
+ it('should emit a helpful message when failed with an Array', function(done){
+ var test = {}, err = [1,2];
+ runner.on('fail', function(test, err){
+ err.message.should.equal('the array [\n 1\n 2\n] was thrown, throw an Error :)');
+ done();
+ });
+ runner.fail(test, err);
+ })
})
describe('.failHook(hook, err)', function(){
@@ -241,5 +290,51 @@ describe('Runner', function(){
runner.failHook(hook, err);
done();
})
- })
-})
+ });
+
+ describe('stackTrace', function() {
+ var stack = [ 'AssertionError: foo bar'
+ , 'at EventEmitter.<anonymous> (/usr/local/dev/test.js:16:12)'
+ , 'at Context.<anonymous> (/usr/local/dev/test.js:19:5)'
+ , 'Test.Runnable.run (/usr/local/lib/node_modules/mocha/lib/runnable.js:244:7)'
+ , 'Runner.runTest (/usr/local/lib/node_modules/mocha/lib/runner.js:374:10)'
+ , '/usr/local/lib/node_modules/mocha/lib/runner.js:452:12'
+ , 'next (/usr/local/lib/node_modules/mocha/lib/runner.js:299:14)'
+ , '/usr/local/lib/node_modules/mocha/lib/runner.js:309:7'
+ , 'next (/usr/local/lib/node_modules/mocha/lib/runner.js:248:23)'
+ , 'Immediate._onImmediate (/usr/local/lib/node_modules/mocha/lib/runner.js:276:5)'
+ , 'at processImmediate [as _immediateCallback] (timers.js:321:17)'];
+
+ describe('shortStackTrace', function() {
+ it('should prettify the stack-trace', function(done) {
+ var hook = {},
+ err = new Error();
+ // Fake stack-trace
+ err.stack = stack.join('\n');
+
+ runner.on('fail', function(hook, err){
+ err.stack.should.equal(stack.slice(0,3).join('\n'));
+ done();
+ });
+ runner.failHook(hook, err);
+ });
+ });
+
+ describe('longStackTrace', function() {
+ it('should display the full stack-trace', function(done) {
+ var hook = {},
+ err = new Error();
+ // Fake stack-trace
+ err.stack = stack.join('\n');
+ // Add --stack-trace option
+ runner.fullStackTrace = true;
+
+ runner.on('fail', function(hook, err){
+ err.stack.should.equal(stack.join('\n'));
+ done();
+ });
+ runner.failHook(hook, err);
+ });
+ });
+ });
+});
diff --git a/test/suite.js b/test/suite.js
index e457d64..011b3fb 100644
--- a/test/suite.js
+++ b/test/suite.js
@@ -1,4 +1,3 @@
-
var mocha = require('../')
, Context = mocha.Context
, Suite = mocha.Suite
diff --git a/test/utils.js b/test/utils.js
index f5ea9dc..524a0e0 100644
--- a/test/utils.js
+++ b/test/utils.js
@@ -1,20 +1,148 @@
-
var mocha = require('..');
var utils = mocha.utils;
-var clean = utils.clean;
-describe('utils', function(){
- describe('.clean()', function(){
- it('should remove the wrapping function declaration', function(){
+describe('utils', function() {
+ describe('.clean()', function() {
+ var clean = utils.clean;
+ 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(){
+ it('should handle newlines in the function declaration', function() {
+ clean('function (one, two, three)\n {\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(){
+ 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() {
+ var isBuffer = utils.isBuffer;
+ it('should test if object is a Buffer', function() {
+ isBuffer(new Buffer([0x01])).should.equal(true);
+ isBuffer({}).should.equal(false);
+ })
+ });
+
+ describe('.map()', function() {
+ var map = utils.map;
+ it('should behave same as Array.prototype.map', function() {
+ var arr = [1, 2, 3];
+ map(arr, JSON.stringify).should.eql(arr.map(JSON.stringify));
+ });
+
+ it('should call the callback with 3 arguments[currentValue, index, array]', function() {
+ var index = 0;
+ map([1, 2, 3], function(e, i, arr) {
+ e.should.equal(arr[index]);
+ i.should.equal(index++);
+ })
+ });
+
+ it('should apply with the given scope', function() {
+ var scope = {};
+ map(['a', 'b', 'c'], function() {
+ this.should.equal(scope);
+ }, scope);
+ });
+ });
+
+ describe('.parseQuery()', function() {
+ var parseQuery = utils.parseQuery;
+ it('should get queryString and return key-value object', function() {
+ parseQuery('?foo=1&bar=2&baz=3').should.eql({
+ foo: 1,
+ bar: 2,
+ baz: 3
+ });
+
+ parseQuery('?r1=^@(?!.*\\)$)&r2=m{2}&r3=^co.*').should.eql({
+ r1: '^@(?!.*\\)$)',
+ r2: 'm{2}',
+ r3: '^co.*'
+ });
})
- })
-})
+ });
+
+ describe('.stackTraceFilter()', function() {
+ describe('on node', function() {
+ var filter = utils.stackTraceFilter();
+ it('should get a stack-trace as a string and prettify it', function() {
+ var stack = [ 'AssertionError: foo bar'
+ , 'at EventEmitter.<anonymous> (/usr/local/dev/test.js:16:12)'
+ , 'at Context.<anonymous> (/usr/local/dev/test.js:19:5)'
+ , 'Test.Runnable.run (/usr/local/lib/node_modules/mocha/lib/runnable.js:244:7)'
+ , 'Runner.runTest (/usr/local/lib/node_modules/mocha/lib/runner.js:374:10)'
+ , '/usr/local/lib/node_modules/mocha/lib/runner.js:452:12'
+ , 'next (/usr/local/lib/node_modules/mocha/lib/runner.js:299:14)'
+ , '/usr/local/lib/node_modules/mocha/lib/runner.js:309:7'
+ , 'next (/usr/local/lib/node_modules/mocha/lib/runner.js:248:23)'
+ , 'Immediate._onImmediate (/usr/local/lib/node_modules/mocha/lib/runner.js:276:5)'
+ , 'at processImmediate [as _immediateCallback] (timers.js:321:17)'];
+ filter(stack.join('\n')).should.equal(stack.slice(0,3).join('\n'));
+
+ stack = [ 'AssertionError: bar baz'
+ , 'at /usr/local/dev/some-test-file.js:25:8'
+ , 'at tryCatcher (/usr/local/dev/own/tmp/node_modules/bluebird/js/main/util.js:24:31)'
+ , 'at Promise._resolveFromResolver (/usr/local/dev/own/tmp/node_modules/bluebird/js/main/promise.js:439:31)'
+ , 'at new Promise (/usr/local/dev/own/tmp/node_modules/bluebird/js/main/promise.js:53:37)'
+ , 'at yourFunction (/usr/local/dev/own/tmp/test1.js:24:13)'
+ , 'at Context.<anonymous> (/usr/local/dev/some-test-file:30:4)'
+ , 'Test.Runnable.run (/usr/local/lib/node_modules/mocha/lib/runnable.js:218:15)'
+ , 'next (/usr/local/lib/node_modules/mocha/lib/runner.js:248:23)'
+ , 'Immediate._onImmediate (/usr/local/lib/node_modules/mocha/lib/runner.js:276:5)'
+ , 'at processImmediate [as _immediateCallback] (timers.js:321:17)'];
+ filter(stack.join('\n')).should.equal(stack.slice(0,2).concat(stack.slice(5,7)).join('\n'));
+ });
+
+ it('should ignore bower and components files', function() {
+ var stack = ['Error: failed'
+ , 'at assert (index.html:11:26)'
+ , 'at Context.<anonymous> (test.js:17:18)'
+ , 'at bower_components/should/should.js:4827:7'
+ , 'at next (file:///.../bower_components/should/should.js:4766:23)'
+ , 'at components/should/5.0.0/should.js:4827:7'
+ , 'at next (file:///.../components/should/5.0.0/should.js:4766:23)'
+ , 'at file:///.../bower_components/mocha/mocha.js:4794:5'
+ , 'at timeslice (.../components/mocha/mocha.js:6218:27)'
+ , 'at Test.require.register.Runnable.run (file:///.../components/mochajs/mocha/2.1.0/mocha.js:4463:15)'
+ , 'at Runner.require.register.Runner.runTest (file:///.../components/mochajs/mocha/2.1.0/mocha.js:4892:10)'
+ , 'at file:///.../components/mochajs/mocha/2.1.0/mocha.js:4970:12'
+ , 'at next (file:///.../components/mochajs/mocha/2.1.0/mocha.js:4817:14)'];
+ filter(stack.join('\n')).should.equal(stack.slice(0,7).join('\n'));
+ });
+ });
+
+ describe('on browser', function() {
+ var filter;
+ before(function() {
+ global.document = true;
+ global.location = { href: 'localhost:3000/foo/bar/index.html' };
+ filter = utils.stackTraceFilter();
+ });
+ it('should strip out bower and components too', function() {
+ var stack = ['Error: failed'
+ , 'at assert (index.html:11:26)'
+ , 'at Context.<anonymous> (test.js:17:18)'
+ , 'at bower_components/should/should.js:4827:7'
+ , 'at next (localhost:3000/foo/bar/bower_components/should/should.js:4766:23)'
+ , 'at components/should/5.0.0/should.js:4827:7'
+ , 'at next (localhost:3000/foo/bar/components/should/5.0.0/should.js:4766:23)'
+ , 'at Runner.require.register.Runner.runTest (localhost:3000/foo/bar/node_modules/mocha.js:4892:10)'
+ , 'at localhost:3000/foo/bar/node_modules/mocha.js:4970:12'
+ , 'at next (localhost:3000/foo/bar/node_modules/mocha.js:4817:14)'];
+ filter(stack.join('\n')).should.equal(stack.slice(0,3).join('\n'));
+ });
+
+ after(function() {
+ delete global.document;
+ delete global.location;
+ });
+ });
+ });
+});
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-mocha.git
More information about the Pkg-javascript-commits
mailing list