diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 911f22c681..d5673232e7 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -1,3 +1,4 @@ +root: true env: node: true browser: true @@ -9,3 +10,6 @@ rules: strict: - error - safe + linebreak-style: + - error + - unix diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..4e63d0ac3d --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,51 @@ +# Mocha Code of Conduct + +## Be friendly and patient +We understand that everyone has different levels of experience or knowledge in many diverse fields, be it technical or +non-technical in nature. We also have areas of knowledge we are eager to expand; we want to be a community where people +can not only contribute, but feel comfortable to ask questions as well and learn along the way. If someone says something +wrong, or says something accidentally offensive, respond with patience and try to keep it polite and civil. Remember that +we all were newbies at one point. + +## Be welcoming +We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not +limited to, members of any race, ethnicity, culture, national origin, color, immigration status, social and economic class, +educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, +religion, and mental and physical ability. + +## Be considerate +Your work will be used by other people, and you in turn will depend on the work of others. Any decision you make will affect +users and colleagues, and you should take those consequences into account when making decisions. Remember that we’re a world-wide +community, so you might not be communicating in someone else’s primary language. + +## Be respectful +Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all +experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important +to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of the JS Foundation +community should be respectful when dealing with other members as well as with people outside the JS Foundation community. + +## Be careful in the words that you choose +We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put +down other participants. Harassment and other exclusionary behavior aren’t acceptable. This includes, but is not limited to: + +* Violent threats or language directed against another person. +* Discriminatory jokes and language. +* Posting sexually explicit or violent material. +* Posting (or threatening to post) other people’s personally identifying information (“doxing”). +* Personal insults, especially those using racist or sexist terms. +* Unwelcome sexual attention. +* Advocating for, or encouraging, any of the above behavior. +* Repeated harassment of others. In general, if someone asks you to stop, then stop. + +## When we disagree, try to understand why +Disagreements, both social and technical, happen all the time and JS Foundation projects are no exception. It is important +that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of the JS +Foundation comes from its varied community, people from a wide range of backgrounds. Different people have different +perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t +forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues +and learning from mistakes. + +Original text courtesy of the Speak Up! project and Django Project. + +## QUESTIONS? +If you have questions, please see the FAQ. If that doesn’t answer your questions, feel free to email conduct@js.foundation. diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000..748e2845f7 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,39 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 120 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 14 +# Issues with these labels will never be considered stale +exemptLabels: + - pr-please + - confirmed + - future + - bug + - chore + - feature + - unconfirmed + - usability + - to-merge + - browser + - reporter + - feature + - documentation + - nice-to-have + - needs-review + - qa + - usability + - semver-minor + - semver-major + - semver-patch + - reporter + - common-mistake +# Label to use when marking an issue as stale +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + I am a bot that watches issues for inactivity. + + This issue hasn't had any recent activity, and I'm labeling it `stale`. In 14 days, if there are no further comments or activity, I will close this issue. + + Thanks for contributing to Mocha! +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.gitignore b/.gitignore index 9b94c5bee0..da8160085d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ npm-debug.log* .nyc_output/ coverage/ BUILDTMP/ +yarn.lock +package-lock.json diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000..b15cbc2c02 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +package-lock=false + diff --git a/.travis.yml b/.travis.yml index 3f03be785a..d5c75c269a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,10 @@ env: matrix: fast_finish: true include: - - node_js: '7' + - node_js: '8' env: TARGET=test-node COVERAGE=true + - node_js: '7' + env: TARGET=test-node - node_js: '6' env: TARGET=test-node - node_js: '5' @@ -31,45 +33,41 @@ matrix: env: TARGET=test-node - node_js: '0.10' env: TARGET=test-node - - node_js: '7' + - node_js: '8' env: TARGET=lint # phantomjs - - node_js: '7' + - node_js: '8' env: TARGET=test-browser # chrome - - node_js: '7' + - node_js: '8' env: TARGET=test-browser BROWSER="chrome@latest" PLATFORM="Windows 8" # edge - - node_js: '7' + - node_js: '8' env: TARGET=test-browser BROWSER="MicrosoftEdge@latest" PLATFORM="Windows 10" # ie11 - - node_js: '7' + - node_js: '8' env: TARGET=test-browser BROWSER="internet explorer@11.0" PLATFORM="Windows 8.1" # ie10 - - node_js: '7' + - node_js: '8' env: TARGET=test-browser BROWSER="internet explorer@10.0" PLATFORM="Windows 8" # ie9 - - node_js: '7' + - node_js: '8' env: TARGET=test-browser BROWSER="internet explorer@9.0" PLATFORM="Windows 7" # ie8 - - node_js: '7' + - node_js: '8' env: TARGET=test-browser BROWSER="internet explorer@8.0" PLATFORM="Windows 7" # ie7 - - node_js: '7' + - node_js: '8' env: TARGET=test-browser BROWSER="internet explorer@7.0" PLATFORM="Windows XP" # firefox - - node_js: '7' + - node_js: '8' env: TARGET=test-browser BROWSER="firefox@latest" PLATFORM="Windows 8.1" # safari - - node_js: '7' + - node_js: '8' env: TARGET=test-browser BROWSER="safari@latest" PLATFORM="OS X 10.11" before_install: scripts/travis-before-install.sh -install: - - npm install - - cd node_modules && ln -nsf @coderbyheart/karma-sauce-launcher karma-sauce-launcher && cd ../ - before_script: scripts/travis-before-script.sh script: make $TARGET diff --git a/CHANGELOG.md b/CHANGELOG.md index 98d445b880..66e5aac8a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,40 @@ +# 3.5.0 / 2017-07-31 + +## :newspaper: News + +- Mocha now has a [code of conduct](https://github.com/mochajs/mocha/blob/master/.github/CODE_OF_CONDUCT.md) (thanks [@kungapal]!). +- Old issues and PRs are now being marked "stale" by [Probot's "Stale" plugin](https://github.com/probot/stale). If an issue is marked as such, and you would like to see it remain open, simply add a new comment to the ticket or PR. +- **WARNING**: Support for non-ES5-compliant environments will be dropped starting with version 4.0.0 of Mocha! + +## :lock: Security Fixes + +- [#2860]: Address [CVE-2015-8315](https://nodesecurity.io/advisories/46) via upgrade of [debug](https://npm.im/debug) ([@boneskull]) + +## :tada: Enhancements + +- [#2696]: Add `--forbid-only` and `--forbid-pending` flags. Use these in CI or hooks to ensure tests aren't accidentally being skipped! ([@charlierudolph]) +- [#2813]: Support Node.js 8's `--napi-modules` flag ([@jupp0r]) + +## :nut_and_bolt: Other + +- Various CI-and-test-related fixes and improvements ([@boneskull], [@dasilvacontin], [@PopradiArpad], [@Munter], [@ScottFreeCode]) +- "Officially" support Node.js 8 ([@elergy]) + +[#2860]: https://github.com/mochajs/mocha/pulls/2860 +[#2696]: https://github.com/mochajs/mocha/pulls/2696 +[#2813]: https://github.com/mochajs/mocha/pulls/2813 +[@charlierudolph]: https://github.com/charlierudolph +[@PopradiArpad]: https://github.com/PopradiArpad +[@kungapal]: https://github.com/kungapal +[@elergy]: https://github.com/elergy +[@jupp0r]: https://github.com/jupp0r + # 3.4.2 / 2017-05-24 ## :bug: Fixes -- [#2802]: Remove call to deprecated os.tmpDir ([@makepanic]) -- [#2820]: Eagerly set process.exitCode ([@chrisleck]) +- [#2802]: Remove call to deprecated `os.tmpDir` ([@makepanic]) +- [#2820]: Eagerly set `process.exitCode` ([@chrisleck]) ## :nut_and_bolt: Other @@ -13,6 +44,7 @@ [@makepanic]: https://github.com/makepanic [@Munter]: https://github.com/Munter +[#2778]: https://github.com/mochajs/mocha/pulls/2778 [#2802]: https://github.com/mochajs/mocha/issues/2802 [#2820]: https://github.com/mochajs/mocha/pull/2820 diff --git a/Makefile b/Makefile index ad8b097e4e..2fa367e8ff 100644 --- a/Makefile +++ b/Makefile @@ -63,79 +63,79 @@ test-jsapi: test-unit: @printf "==> [Test :: Unit]\n" - $(call test_node,unit) test/acceptance/*.js \ - --growl \ - test/*.js + $(call test_node,unit) test/unit/*.spec.js \ + test/node-unit/*.spec.js \ + --growl test-integration: @printf "==> [Test :: Integrations]\n" $(call test_node,integration) --timeout 5000 \ - test/integration/*.js + test/integration/*.spec.js test-compilers: @printf "==> [Test :: Compilers]\n" $(call test_node,compilers) --compilers coffee:coffee-script/register,foo:./test/compiler/foo \ - test/acceptance/test.coffee \ - test/acceptance/test.foo + test/compiler/test.coffee \ + test/compiler/test.foo test-requires: @printf "==> [Test :: Requires]\n" $(call test_node,requires) --compilers coffee:coffee-script/register \ - --require test/acceptance/require/a.js \ - --require test/acceptance/require/b.coffee \ - --require test/acceptance/require/c.js \ - --require test/acceptance/require/d.coffee \ - test/acceptance/require/require.spec.js + --require test/require/a.js \ + --require test/require/b.coffee \ + --require test/require/c.js \ + --require test/require/d.coffee \ + test/require/require.spec.js test-bdd: @printf "==> [Test :: BDD]\n" $(call test_node,bdd) --ui bdd \ - test/acceptance/interfaces/bdd.spec + test/interfaces/bdd.spec test-tdd: @printf "==> [Test :: TDD]\n" $(call test_node,tdd) --ui tdd \ - test/acceptance/interfaces/tdd.spec + test/interfaces/tdd.spec test-qunit: @printf "==> [Test :: QUnit]\n" $(call test_node,qunit) --ui qunit \ - test/acceptance/interfaces/qunit.spec + test/interfaces/qunit.spec test-exports: @printf "==> [Test :: Exports]\n" $(call test_node,exports) --ui exports \ - test/acceptance/interfaces/exports.spec + test/interfaces/exports.spec test-glob: @printf "==> [Test :: Glob]\n" - bash ./test/acceptance/glob/glob.sh + bash ./test/glob/glob.sh test-reporters: @printf "==> [Test :: Reporters]\n" - $(call test_node,reporters) test/reporters/*.js + $(call test_node,reporters) test/reporters/*.spec.js test-only: @printf "==> [Test :: Only]\n" $(call test_node,only-tdd) --ui tdd \ - test/acceptance/misc/only/tdd.spec + test/misc/only/tdd.spec $(call test_node,only-bdd) --ui bdd \ - test/acceptance/misc/only/bdd.spec + test/misc/only/bdd.spec $(call test_node,only-bdd-require) --ui qunit \ - test/acceptance/misc/only/bdd-require.spec + test/misc/only/bdd-require.spec test-global-only: @printf "==> [Test :: Global Only]\n" $(call test_node,global-only-tdd) --ui tdd \ - test/acceptance/misc/only/global/tdd.spec + test/misc/only/global/tdd.spec $(call test_node,global-only-bdd) --ui bdd \ - test/acceptance/misc/only/global/bdd.spec + test/misc/only/global/bdd.spec $(call test_node,global-only-qunit) --ui qunit \ - test/acceptance/misc/only/global/qunit.spec + test/misc/only/global/qunit.spec test-mocha: @printf "==> [Test :: Mocha]\n" @@ -144,19 +144,19 @@ test-mocha: non-tty: @printf "==> [Test :: Non-TTY]\n" $(call test_node,non-tty-dot) --reporter dot \ - test/acceptance/interfaces/bdd.spec 2>&1 > /tmp/dot.out + test/interfaces/bdd.spec 2>&1 > /tmp/dot.out @echo dot: @cat /tmp/dot.out $(call test_node,non-tty-list) --reporter list \ - test/acceptance/interfaces/bdd.spec 2>&1 > /tmp/list.out + test/interfaces/bdd.spec 2>&1 > /tmp/list.out @echo list: @cat /tmp/list.out $(call test_node,non-tty-spec) --reporter spec \ - test/acceptance/interfaces/bdd.spec 2>&1 > /tmp/spec.out + test/interfaces/bdd.spec 2>&1 > /tmp/spec.out @echo spec: @cat /tmp/spec.out diff --git a/README.md b/README.md index baaeb5bf9e..9e4d4dcbea 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,9 @@ 1. Increase test coverage on Node.js and browser - Increase integration coverage for all reporters - `html` reporter must be tested in browser - - Basic console reporters (*not* `nyan`, `landing`, etc.) must be tested in **both** browser and Node.js contexts; PhantomJS can consume all console reporters - - Filesystem-based reporters must be tested in Node.js context + - ~~Basic console reporters (*not* `nyan`, `landing`, etc.) must be tested in **both** browser and Node.js contexts; PhantomJS can consume all console reporters~~ + - ~~Filesystem-based reporters must be tested in Node.js context~~ + - **UPDATE - May 24 2017**: Thanks to [community contributions](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md#mag-coverage), the coverage on most reporters has increased dramatically! The `html` reporter is still in [dire need of coverage](https://coveralls.io/builds/11674428/source?filename=lib%2Freporters%2Fhtml.js). - Increase coverage against all interfaces (`exports` in particular). Ideally this becomes a "matrix" where we repeat sets of integration tests across all interfaces. - Refactor non-Node.js-specific tests to allow them to run in a browser context. Node.js-specific tests include those which *require* the CLI or filesystem. Most everything else is fair game. 2. Review current open pull requests @@ -20,7 +21,7 @@ - Pull requests **must** have supporting tests. The only exceptions are pure cosmetic or non-functional changes. - Pull request contributors must sign the CLA. 3. Close old, inactive issues and pull requests - - A bot should do this. We need a bot. Got a bot? + - ~~A bot should do this. We need a bot. Got a bot?~~ We now use GitHub's own [probot-stale](https://www.npmjs.com/package/probot-stale). 4. Triage issues - If we run into "critical" bugs, they need fixing. - "Critical" means Mocha is broken w/o workarounds for a *large percentage* of users diff --git a/appveyor.yml b/appveyor.yml index 6a2a6e1811..ff832db835 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,6 @@ environment: matrix: + - nodejs_version: '8' - nodejs_version: '7' - nodejs_version: '6' - nodejs_version: '4' diff --git a/bin/_mocha b/bin/_mocha index 7f3d01aa1d..c37d49fef5 100755 --- a/bin/_mocha +++ b/bin/_mocha @@ -99,6 +99,7 @@ program .option('--no-warnings', 'silence all node process warnings') .option('--opts ', 'specify opts path', 'test/mocha.opts') .option('--perf-basic-prof', 'enable perf linux profiler (basic support)') + .option('--napi-modules', 'enable experimental NAPI modules') .option('--prof', 'log statistical profiling information') .option('--log-timer-events', 'Time events including external callbacks') .option('--recursive', 'include sub directories') @@ -111,7 +112,9 @@ program .option('--use_strict', 'enforce strict mode') .option('--watch-extensions ,...', 'additional extensions to monitor with --watch', list, []) .option('--delay', 'wait for async suite definition') - .option('--allow-uncaught', 'enable uncaught errors to propagate'); + .option('--allow-uncaught', 'enable uncaught errors to propagate') + .option('--forbid-only', 'causes test marked with only to fail the suite') + .option('--forbid-pending', 'causes pending tests and test marked with skip to fail the suite'); program._name = 'mocha'; @@ -333,6 +336,14 @@ if (program.retries) { mocha.suite.retries(program.retries); } +// --forbid-only + +if (program.forbidOnly) mocha.forbidOnly(); + +// --forbid-pending + +if (program.forbidPending) mocha.forbidPending(); + // custom compiler support var extensions = ['js']; diff --git a/bin/mocha b/bin/mocha index 8ba64a0a06..d632fbc394 100755 --- a/bin/mocha +++ b/bin/mocha @@ -48,6 +48,7 @@ process.argv.slice(2).forEach(function (arg) { case '--use_strict': case '--allow-natives-syntax': case '--perf-basic-prof': + case '--napi-modules': args.unshift(arg); break; default: diff --git a/karma.conf.js b/karma.conf.js index 30d5714665..b8d73fd0e3 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -4,6 +4,7 @@ var fs = require('fs'); var path = require('path'); var mkdirp = require('mkdirp'); var baseBundleDirpath = path.join(__dirname, '.karma'); +var osName = require('os-name'); module.exports = function (config) { var bundleDirpath; @@ -13,18 +14,20 @@ module.exports = function (config) { 'expect', 'mocha' ], + plugins: [ + 'karma-browserify', + 'karma-chrome-launcher', + 'karma-phantomjs-launcher', + 'karma-expect', + 'karma-mocha', + 'karma-spec-reporter', + require('@coderbyheart/karma-sauce-launcher') + ], files: [ // we use the BDD interface for all of the tests that // aren't interface-specific. 'test/browser-fixtures/bdd.fixture.js', - 'test/acceptance/*.spec.js' - ], - exclude: [ - 'test/acceptance/http.spec.js', - 'test/acceptance/fs.spec.js', - 'test/acceptance/file-utils.spec.js', - 'test/acceptance/require/**/*.js', - 'test/acceptance/misc/**/*.js' + 'test/unit/*.spec.js' ], preprocessors: { 'test/**/*.js': ['browserify'] @@ -47,7 +50,7 @@ module.exports = function (config) { }, reporters: ['spec'], colors: true, - browsers: ['PhantomJS'], // This is the default browser to run, locally + browsers: [osName() === 'macOS Sierra' ? 'Chrome' : 'PhantomJS'], // This is the default browser to run, locally logLevel: config.LOG_INFO, client: { mocha: { @@ -127,7 +130,7 @@ module.exports = function (config) { } cfg.files = [ 'test/browser-fixtures/' + ui + '.fixture.js', - 'test/acceptance/interfaces/' + ui + '.spec.js' + 'test/interfaces/' + ui + '.spec.js' ]; } else if (cfg.sauceLabs) { cfg.sauceLabs.testName = 'Unit Tests'; diff --git a/lib/mocha.js b/lib/mocha.js index 8bacf27b17..bfc0238d46 100644 --- a/lib/mocha.js +++ b/lib/mocha.js @@ -483,6 +483,24 @@ Mocha.prototype.delay = function delay () { return this; }; +/** + * Tests marked only fail the suite + * @returns {Mocha} + */ +Mocha.prototype.forbidOnly = function () { + this.options.forbidOnly = true; + return this; +}; + +/** + * Pending tests and tests marked skip fail the suite + * @returns {Mocha} + */ +Mocha.prototype.forbidPending = function () { + this.options.forbidPending = true; + return this; +}; + /** * Run tests and invoke `fn()` when complete. * @@ -504,6 +522,8 @@ Mocha.prototype.run = function (fn) { runner.hasOnly = options.hasOnly; runner.asyncOnly = options.asyncOnly; runner.allowUncaught = options.allowUncaught; + runner.forbidOnly = options.forbidOnly; + runner.forbidPending = options.forbidPending; if (options.grep) { runner.grep(options.grep, options.invert); } diff --git a/lib/runner.js b/lib/runner.js index b024e0dcb5..039065a2e0 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -820,6 +820,12 @@ Runner.prototype.run = function (fn) { // callback this.on('end', function () { + if (self.forbidOnly && self.hasOnly) { + self.failures += self.stats.tests; + } + if (self.forbidPending) { + self.failures += self.stats.pending; + } debug('end'); process.removeListener('uncaughtException', uncaught); fn(self.failures); diff --git a/mocha.js b/mocha.js index 4e59d156cf..2ad1356722 100644 --- a/mocha.js +++ b/mocha.js @@ -189,7 +189,7 @@ global.mocha = mocha; module.exports = global; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./lib/mocha":14,"_process":82,"browser-stdout":41}],2:[function(require,module,exports){ +},{"./lib/mocha":14,"_process":81,"browser-stdout":41}],2:[function(require,module,exports){ 'use strict'; function noop () {} @@ -647,7 +647,7 @@ Context.prototype.inspect = function () { }, 2); }; -},{"json3":69}],7:[function(require,module,exports){ +},{"json3":68}],7:[function(require,module,exports){ 'use strict'; /** @@ -1743,6 +1743,24 @@ Mocha.prototype.delay = function delay () { return this; }; +/** + * Tests marked only fail the suite + * @returns {Mocha} + */ +Mocha.prototype.forbidOnly = function () { + this.options.forbidOnly = true; + return this; +}; + +/** + * Pending tests and tests marked skip fail the suite + * @returns {Mocha} + */ +Mocha.prototype.forbidPending = function () { + this.options.forbidPending = true; + return this; +}; + /** * Run tests and invoke `fn()` when complete. * @@ -1764,6 +1782,8 @@ Mocha.prototype.run = function (fn) { runner.hasOnly = options.hasOnly; runner.asyncOnly = options.asyncOnly; runner.allowUncaught = options.allowUncaught; + runner.forbidOnly = options.forbidOnly; + runner.forbidPending = options.forbidPending; if (options.grep) { runner.grep(options.grep, options.invert); } @@ -1790,7 +1810,7 @@ Mocha.prototype.run = function (fn) { }; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/lib") -},{"./context":6,"./hook":7,"./interfaces":11,"./reporters":21,"./runnable":33,"./runner":34,"./suite":35,"./test":36,"./utils":38,"_process":82,"escape-string-regexp":62,"growl":64,"path":42}],15:[function(require,module,exports){ +},{"./context":6,"./hook":7,"./interfaces":11,"./reporters":21,"./runnable":33,"./runner":34,"./suite":35,"./test":36,"./utils":38,"_process":81,"escape-string-regexp":61,"growl":63,"path":42}],15:[function(require,module,exports){ 'use strict'; /** @@ -2435,7 +2455,7 @@ function sameType (a, b) { } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../ms":15,"../utils":38,"_process":82,"diff":56,"supports-color":42,"tty":5}],18:[function(require,module,exports){ +},{"../ms":15,"../utils":38,"_process":81,"diff":55,"supports-color":42,"tty":5}],18:[function(require,module,exports){ 'use strict'; /** @@ -2573,7 +2593,7 @@ function Dot (runner) { inherits(Dot, Base); }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":82}],20:[function(require,module,exports){ +},{"../utils":38,"./base":17,"_process":81}],20:[function(require,module,exports){ (function (global){ 'use strict'; @@ -2925,7 +2945,7 @@ function on (el, event, fn) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../browser/progress":4,"../utils":38,"./base":17,"escape-string-regexp":62}],21:[function(require,module,exports){ +},{"../browser/progress":4,"../utils":38,"./base":17,"escape-string-regexp":61}],21:[function(require,module,exports){ 'use strict'; // Alias exports to a their normalized format Mocha#reporter to prevent a need @@ -3013,7 +3033,7 @@ function clean (test) { } }).call(this,require('_process')) -},{"./base":17,"_process":82,"json3":69}],23:[function(require,module,exports){ +},{"./base":17,"_process":81,"json3":68}],23:[function(require,module,exports){ (function (process){ 'use strict'; @@ -3109,7 +3129,7 @@ function errorJSON (err) { } }).call(this,require('_process')) -},{"./base":17,"_process":82}],24:[function(require,module,exports){ +},{"./base":17,"_process":81}],24:[function(require,module,exports){ (function (process){ 'use strict'; @@ -3207,7 +3227,7 @@ function Landing (runner) { inherits(Landing, Base); }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":82}],25:[function(require,module,exports){ +},{"../utils":38,"./base":17,"_process":81}],25:[function(require,module,exports){ (function (process){ 'use strict'; @@ -3274,7 +3294,7 @@ function List (runner) { inherits(List, Base); }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":82}],26:[function(require,module,exports){ +},{"../utils":38,"./base":17,"_process":81}],26:[function(require,module,exports){ (function (process){ 'use strict'; @@ -3377,7 +3397,7 @@ function Markdown (runner) { } }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":82}],27:[function(require,module,exports){ +},{"../utils":38,"./base":17,"_process":81}],27:[function(require,module,exports){ (function (process){ 'use strict'; @@ -3419,7 +3439,7 @@ function Min (runner) { inherits(Min, Base); }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":82}],28:[function(require,module,exports){ +},{"../utils":38,"./base":17,"_process":81}],28:[function(require,module,exports){ (function (process){ 'use strict'; @@ -3686,7 +3706,7 @@ function write (string) { } }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":82}],29:[function(require,module,exports){ +},{"../utils":38,"./base":17,"_process":81}],29:[function(require,module,exports){ (function (process){ 'use strict'; @@ -3781,7 +3801,7 @@ function Progress (runner, options) { inherits(Progress, Base); }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":82}],30:[function(require,module,exports){ +},{"../utils":38,"./base":17,"_process":81}],30:[function(require,module,exports){ 'use strict'; /** @@ -4108,7 +4128,7 @@ function tag (name, attrs, close, content) { } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../utils":38,"./base":17,"_process":82,"fs":42,"mkdirp":79,"path":42}],33:[function(require,module,exports){ +},{"../utils":38,"./base":17,"_process":81,"fs":42,"mkdirp":78,"path":42}],33:[function(require,module,exports){ (function (global){ 'use strict'; @@ -4501,7 +4521,7 @@ Runnable.prototype.run = function (fn) { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./ms":15,"./pending":16,"./utils":38,"debug":2,"events":3,"json3":69,"lodash.create":75}],34:[function(require,module,exports){ +},{"./ms":15,"./pending":16,"./utils":38,"debug":2,"events":3,"json3":68,"lodash.create":69}],34:[function(require,module,exports){ (function (process,global){ 'use strict'; @@ -5325,6 +5345,12 @@ Runner.prototype.run = function (fn) { // callback this.on('end', function () { + if (self.forbidOnly && self.hasOnly) { + self.failures += self.stats.tests; + } + if (self.forbidPending) { + self.failures += self.stats.pending; + } debug('end'); process.removeListener('uncaughtException', uncaught); fn(self.failures); @@ -5467,7 +5493,7 @@ function extraGlobals () { } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./pending":16,"./runnable":33,"./utils":38,"_process":82,"debug":2,"events":3}],35:[function(require,module,exports){ +},{"./pending":16,"./runnable":33,"./utils":38,"_process":81,"debug":2,"events":3}],35:[function(require,module,exports){ 'use strict'; /** @@ -5925,7 +5951,7 @@ Test.prototype.clone = function () { return test; }; -},{"./runnable":33,"./utils":38,"lodash.create":75}],37:[function(require,module,exports){ +},{"./runnable":33,"./utils":38,"lodash.create":69}],37:[function(require,module,exports){ 'use strict'; /** @@ -6775,7 +6801,7 @@ exports.isPromise = function isPromise (value) { exports.noop = function () {}; }).call(this,require('_process'),require("buffer").Buffer) -},{"./to-iso-string":37,"_process":82,"buffer":44,"debug":2,"fs":42,"glob":42,"json3":69,"path":42,"util":99}],39:[function(require,module,exports){ +},{"./to-iso-string":37,"_process":81,"buffer":43,"debug":2,"fs":42,"glob":42,"json3":68,"path":42,"util":101}],39:[function(require,module,exports){ 'use strict' exports.byteLength = byteLength @@ -6811,22 +6837,22 @@ function placeHoldersCount (b64) { function byteLength (b64) { // base64 is 4/3 + up to two characters of the original data - return b64.length * 3 / 4 - placeHoldersCount(b64) + return (b64.length * 3 / 4) - placeHoldersCount(b64) } function toByteArray (b64) { - var i, j, l, tmp, placeHolders, arr + var i, l, tmp, placeHolders, arr var len = b64.length placeHolders = placeHoldersCount(b64) - arr = new Arr(len * 3 / 4 - placeHolders) + arr = new Arr((len * 3 / 4) - placeHolders) // if there are placeholders, only get up to the last complete 4 chars l = placeHolders > 0 ? len - 4 : len var L = 0 - for (i = 0, j = 0; i < l; i += 4, j += 3) { + for (i = 0; i < l; i += 4) { tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] arr[L++] = (tmp >> 16) & 0xFF arr[L++] = (tmp >> 8) & 0xFF @@ -6922,122 +6948,10 @@ BrowserStdout.prototype._write = function(chunks, encoding, cb) { } }).call(this,require('_process')) -},{"_process":82,"stream":94,"util":99}],42:[function(require,module,exports){ +},{"_process":81,"stream":95,"util":101}],42:[function(require,module,exports){ arguments[4][40][0].apply(exports,arguments) },{"dup":40}],43:[function(require,module,exports){ (function (global){ -'use strict'; - -var buffer = require('buffer'); -var Buffer = buffer.Buffer; -var SlowBuffer = buffer.SlowBuffer; -var MAX_LEN = buffer.kMaxLength || 2147483647; -exports.alloc = function alloc(size, fill, encoding) { - if (typeof Buffer.alloc === 'function') { - return Buffer.alloc(size, fill, encoding); - } - if (typeof encoding === 'number') { - throw new TypeError('encoding must not be number'); - } - if (typeof size !== 'number') { - throw new TypeError('size must be a number'); - } - if (size > MAX_LEN) { - throw new RangeError('size is too large'); - } - var enc = encoding; - var _fill = fill; - if (_fill === undefined) { - enc = undefined; - _fill = 0; - } - var buf = new Buffer(size); - if (typeof _fill === 'string') { - var fillBuf = new Buffer(_fill, enc); - var flen = fillBuf.length; - var i = -1; - while (++i < size) { - buf[i] = fillBuf[i % flen]; - } - } else { - buf.fill(_fill); - } - return buf; -} -exports.allocUnsafe = function allocUnsafe(size) { - if (typeof Buffer.allocUnsafe === 'function') { - return Buffer.allocUnsafe(size); - } - if (typeof size !== 'number') { - throw new TypeError('size must be a number'); - } - if (size > MAX_LEN) { - throw new RangeError('size is too large'); - } - return new Buffer(size); -} -exports.from = function from(value, encodingOrOffset, length) { - if (typeof Buffer.from === 'function' && (!global.Uint8Array || Uint8Array.from !== Buffer.from)) { - return Buffer.from(value, encodingOrOffset, length); - } - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number'); - } - if (typeof value === 'string') { - return new Buffer(value, encodingOrOffset); - } - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - var offset = encodingOrOffset; - if (arguments.length === 1) { - return new Buffer(value); - } - if (typeof offset === 'undefined') { - offset = 0; - } - var len = length; - if (typeof len === 'undefined') { - len = value.byteLength - offset; - } - if (offset >= value.byteLength) { - throw new RangeError('\'offset\' is out of bounds'); - } - if (len > value.byteLength - offset) { - throw new RangeError('\'length\' is out of bounds'); - } - return new Buffer(value.slice(offset, offset + len)); - } - if (Buffer.isBuffer(value)) { - var out = new Buffer(value.length); - value.copy(out, 0, 0, value.length); - return out; - } - if (value) { - if (Array.isArray(value) || (typeof ArrayBuffer !== 'undefined' && value.buffer instanceof ArrayBuffer) || 'length' in value) { - return new Buffer(value); - } - if (value.type === 'Buffer' && Array.isArray(value.data)) { - return new Buffer(value.data); - } - } - - throw new TypeError('First argument must be a string, Buffer, ' + 'ArrayBuffer, Array, or array-like object.'); -} -exports.allocUnsafeSlow = function allocUnsafeSlow(size) { - if (typeof Buffer.allocUnsafeSlow === 'function') { - return Buffer.allocUnsafeSlow(size); - } - if (typeof size !== 'number') { - throw new TypeError('size must be a number'); - } - if (size >= MAX_LEN) { - throw new RangeError('size is too large'); - } - return new SlowBuffer(size); -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"buffer":44}],44:[function(require,module,exports){ -(function (global){ /*! * The buffer module from node.js, for the browser. * @@ -8829,7 +8743,7 @@ function isnan (val) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"base64-js":39,"ieee754":65,"isarray":68}],45:[function(require,module,exports){ +},{"base64-js":39,"ieee754":64,"isarray":67}],44:[function(require,module,exports){ (function (Buffer){ // Copyright Joyent, Inc. and other Node contributors. // @@ -8940,7 +8854,7 @@ function objectToString(o) { } }).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":67}],46:[function(require,module,exports){ +},{"../../is-buffer/index.js":66}],45:[function(require,module,exports){ /*istanbul ignore start*/"use strict"; exports.__esModule = true; @@ -8966,7 +8880,7 @@ function convertChangesToDMP(changes) { } -},{}],47:[function(require,module,exports){ +},{}],46:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9003,7 +8917,7 @@ function escapeHTML(s) { } -},{}],48:[function(require,module,exports){ +},{}],47:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9027,7 +8941,7 @@ function diffArrays(oldArr, newArr, callback) { } -},{"./base":49}],49:[function(require,module,exports){ +},{"./base":48}],48:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9259,7 +9173,7 @@ function clonePath(path) { } -},{}],50:[function(require,module,exports){ +},{}],49:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9279,7 +9193,7 @@ function diffChars(oldStr, newStr, callback) { } -},{"./base":49}],51:[function(require,module,exports){ +},{"./base":48}],50:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9303,7 +9217,7 @@ function diffCss(oldStr, newStr, callback) { } -},{"./base":49}],52:[function(require,module,exports){ +},{"./base":48}],51:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9414,7 +9328,7 @@ function canonicalize(obj, stack, replacementStack) { } -},{"./base":49,"./line":53}],53:[function(require,module,exports){ +},{"./base":48,"./line":52}],52:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9469,7 +9383,7 @@ function diffTrimmedLines(oldStr, newStr, callback) { } -},{"../util/params":61,"./base":49}],54:[function(require,module,exports){ +},{"../util/params":60,"./base":48}],53:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9493,7 +9407,7 @@ function diffSentences(oldStr, newStr, callback) { } -},{"./base":49}],55:[function(require,module,exports){ +},{"./base":48}],54:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9565,7 +9479,7 @@ function diffWordsWithSpace(oldStr, newStr, callback) { } -},{"../util/params":61,"./base":49}],56:[function(require,module,exports){ +},{"../util/params":60,"./base":48}],55:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9640,7 +9554,7 @@ exports. /*istanbul ignore end*/Diff = _base2['default']; */ -},{"./convert/dmp":46,"./convert/xml":47,"./diff/array":48,"./diff/base":49,"./diff/character":50,"./diff/css":51,"./diff/json":52,"./diff/line":53,"./diff/sentence":54,"./diff/word":55,"./patch/apply":57,"./patch/create":58,"./patch/parse":59}],57:[function(require,module,exports){ +},{"./convert/dmp":45,"./convert/xml":46,"./diff/array":47,"./diff/base":48,"./diff/character":49,"./diff/css":50,"./diff/json":51,"./diff/line":52,"./diff/sentence":53,"./diff/word":54,"./patch/apply":56,"./patch/create":57,"./patch/parse":58}],56:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9819,7 +9733,7 @@ function applyPatches(uniDiff, options) { } -},{"../util/distance-iterator":60,"./parse":59}],58:[function(require,module,exports){ +},{"../util/distance-iterator":59,"./parse":58}],57:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -9977,7 +9891,7 @@ function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) { } -},{"../diff/line":53}],59:[function(require,module,exports){ +},{"../diff/line":52}],58:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -10122,7 +10036,7 @@ function parsePatch(uniDiff) { } -},{}],60:[function(require,module,exports){ +},{}],59:[function(require,module,exports){ /*istanbul ignore start*/"use strict"; exports.__esModule = true; @@ -10171,7 +10085,7 @@ exports["default"] = /*istanbul ignore end*/function (start, minLine, maxLine) { }; -},{}],61:[function(require,module,exports){ +},{}],60:[function(require,module,exports){ /*istanbul ignore start*/'use strict'; exports.__esModule = true; @@ -10191,7 +10105,7 @@ function generateOptions(options, defaults) { } -},{}],62:[function(require,module,exports){ +},{}],61:[function(require,module,exports){ 'use strict'; var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; @@ -10204,7 +10118,7 @@ module.exports = function (str) { return str.replace(matchOperatorsRe, '\\$&'); }; -},{}],63:[function(require,module,exports){ +},{}],62:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -10508,7 +10422,7 @@ function isUndefined(arg) { return arg === void 0; } -},{}],64:[function(require,module,exports){ +},{}],63:[function(require,module,exports){ (function (process){ // Growl - Copyright TJ Holowaychuk (MIT Licensed) @@ -10802,7 +10716,7 @@ function growl(msg, options, fn) { }; }).call(this,require('_process')) -},{"_process":82,"child_process":42,"fs":42,"os":80,"path":42}],65:[function(require,module,exports){ +},{"_process":81,"child_process":42,"fs":42,"os":79,"path":42}],64:[function(require,module,exports){ exports.read = function (buffer, offset, isLE, mLen, nBytes) { var e, m var eLen = nBytes * 8 - mLen - 1 @@ -10888,7 +10802,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { buffer[offset + i - d] |= s * 128 } -},{}],66:[function(require,module,exports){ +},{}],65:[function(require,module,exports){ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { @@ -10913,7 +10827,7 @@ if (typeof Object.create === 'function') { } } -},{}],67:[function(require,module,exports){ +},{}],66:[function(require,module,exports){ /*! * Determine if an object is a Buffer * @@ -10936,14 +10850,14 @@ function isSlowBuffer (obj) { return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) } -},{}],68:[function(require,module,exports){ +},{}],67:[function(require,module,exports){ var toString = {}.toString; module.exports = Array.isArray || function (arr) { return toString.call(arr) == '[object Array]'; }; -},{}],69:[function(require,module,exports){ +},{}],68:[function(require,module,exports){ (function (global){ /*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */ ;(function () { @@ -11849,7 +11763,64 @@ module.exports = Array.isArray || function (arr) { }).call(this); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],70:[function(require,module,exports){ +},{}],69:[function(require,module,exports){ +/** + * lodash 3.1.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseAssign = require('lodash._baseassign'), + baseCreate = require('lodash._basecreate'), + isIterateeCall = require('lodash._isiterateecall'); + +/** + * Creates an object that inherits from the given `prototype` object. If a + * `properties` object is provided its own enumerable properties are assigned + * to the created object. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { + * 'constructor': Circle + * }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ +function create(prototype, properties, guard) { + var result = baseCreate(prototype); + if (guard && isIterateeCall(prototype, properties, guard)) { + properties = undefined; + } + return properties ? baseAssign(result, properties) : result; +} + +module.exports = create; + +},{"lodash._baseassign":70,"lodash._basecreate":76,"lodash._isiterateecall":77}],70:[function(require,module,exports){ /** * lodash 3.2.0 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -11878,7 +11849,7 @@ function baseAssign(object, source) { module.exports = baseAssign; -},{"lodash._basecopy":71,"lodash.keys":78}],71:[function(require,module,exports){ +},{"lodash._basecopy":71,"lodash.keys":72}],71:[function(require,module,exports){ /** * lodash 3.0.1 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -11914,33 +11885,125 @@ module.exports = baseCopy; },{}],72:[function(require,module,exports){ /** - * lodash 3.0.3 (Custom Build) + * lodash 3.1.2 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ +var getNative = require('lodash._getnative'), + isArguments = require('lodash.isarguments'), + isArray = require('lodash.isarray'); + +/** Used to detect unsigned integer values. */ +var reIsUint = /^\d+$/; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeKeys = getNative(Object, 'keys'); + +/** + * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. + * The base implementation of `_.property` without support for deep paths. * * @private - * @param {Object} prototype The object to inherit from. - * @returns {Object} Returns the new object. + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. */ -var baseCreate = (function() { - function object() {} - return function(prototype) { - if (isObject(prototype)) { - object.prototype = prototype; - var result = new object; - object.prototype = undefined; - } - return result || {}; +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; }; -}()); +} + +/** + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. + * + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. + */ +var getLength = baseProperty('length'); + +/** + * Checks if `value` is array-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + */ +function isArrayLike(value) { + return value != null && isLength(getLength(value)); +} + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; + length = length == null ? MAX_SAFE_INTEGER : length; + return value > -1 && value % 1 == 0 && value < length; +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * A fallback implementation of `Object.keys` which creates an array of the + * own enumerable property names of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function shimKeys(object) { + var props = keysIn(object), + propsLength = props.length, + length = propsLength && object.length; + + var allowIndexes = !!length && isLength(length) && + (isArray(object) || isArguments(object)); + + var index = -1, + result = []; + + while (++index < propsLength) { + var key = props[index]; + if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { + result.push(key); + } + } + return result; +} /** * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. @@ -11969,11 +12032,98 @@ function isObject(value) { return !!value && (type == 'object' || type == 'function'); } -module.exports = baseCreate; - -},{}],73:[function(require,module,exports){ /** - * lodash 3.9.1 (Custom Build) + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) + * for more details. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +var keys = !nativeKeys ? shimKeys : function(object) { + var Ctor = object == null ? undefined : object.constructor; + if ((typeof Ctor == 'function' && Ctor.prototype === object) || + (typeof object != 'function' && isArrayLike(object))) { + return shimKeys(object); + } + return isObject(object) ? nativeKeys(object) : []; +}; + +/** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ +function keysIn(object) { + if (object == null) { + return []; + } + if (!isObject(object)) { + object = Object(object); + } + var length = object.length; + length = (length && isLength(length) && + (isArray(object) || isArguments(object)) && length) || 0; + + var Ctor = object.constructor, + index = -1, + isProto = typeof Ctor == 'function' && Ctor.prototype === object, + result = Array(length), + skipIndexes = length > 0; + + while (++index < length) { + result[index] = (index + ''); + } + for (var key in object) { + if (!(skipIndexes && isIndex(key, length)) && + !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; +} + +module.exports = keys; + +},{"lodash._getnative":73,"lodash.isarguments":74,"lodash.isarray":75}],73:[function(require,module,exports){ +/** + * lodash 3.9.1 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 @@ -12111,197 +12261,6 @@ function isNative(value) { module.exports = getNative; },{}],74:[function(require,module,exports){ -/** - * lodash 3.0.9 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** Used to detect unsigned integer values. */ -var reIsUint = /^\d+$/; - -/** - * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) - * of an array-like value. - */ -var MAX_SAFE_INTEGER = 9007199254740991; - -/** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new function. - */ -function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; -} - -/** - * Gets the "length" property value of `object`. - * - * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) - * that affects Safari on at least iOS 8.1-8.3 ARM64. - * - * @private - * @param {Object} object The object to query. - * @returns {*} Returns the "length" value. - */ -var getLength = baseProperty('length'); - -/** - * Checks if `value` is array-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - */ -function isArrayLike(value) { - return value != null && isLength(getLength(value)); -} - -/** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ -function isIndex(value, length) { - value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; - length = length == null ? MAX_SAFE_INTEGER : length; - return value > -1 && value % 1 == 0 && value < length; -} - -/** - * Checks if the provided arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. - */ -function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object)) { - var other = object[index]; - return value === value ? (value === other) : (other !== other); - } - return false; -} - -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - */ -function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; -} - -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} - -module.exports = isIterateeCall; - -},{}],75:[function(require,module,exports){ -/** - * lodash 3.1.1 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var baseAssign = require('lodash._baseassign'), - baseCreate = require('lodash._basecreate'), - isIterateeCall = require('lodash._isiterateecall'); - -/** - * Creates an object that inherits from the given `prototype` object. If a - * `properties` object is provided its own enumerable properties are assigned - * to the created object. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ -function create(prototype, properties, guard) { - var result = baseCreate(prototype); - if (guard && isIterateeCall(prototype, properties, guard)) { - properties = undefined; - } - return properties ? baseAssign(result, properties) : result; -} - -module.exports = create; - -},{"lodash._baseassign":70,"lodash._basecreate":72,"lodash._isiterateecall":74}],76:[function(require,module,exports){ /** * lodash (Custom Build) * Build: `lodash modularize exports="npm" -o ./` @@ -12532,7 +12491,7 @@ function isObjectLike(value) { module.exports = isArguments; -},{}],77:[function(require,module,exports){ +},{}],75:[function(require,module,exports){ /** * lodash 3.0.4 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` @@ -12714,33 +12673,80 @@ function isNative(value) { module.exports = isArray; -},{}],78:[function(require,module,exports){ +},{}],76:[function(require,module,exports){ /** - * lodash 3.1.2 (Custom Build) + * lodash 3.0.3 (Custom Build) * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license */ -var getNative = require('lodash._getnative'), - isArguments = require('lodash.isarguments'), - isArray = require('lodash.isarray'); -/** Used to detect unsigned integer values. */ -var reIsUint = /^\d+$/; +/** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} prototype The object to inherit from. + * @returns {Object} Returns the new object. + */ +var baseCreate = (function() { + function object() {} + return function(prototype) { + if (isObject(prototype)) { + object.prototype = prototype; + var result = new object; + object.prototype = undefined; + } + return result || {}; + }; +}()); -/** Used for native method references. */ -var objectProto = Object.prototype; +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; +module.exports = baseCreate; -/* Native method references for those with the same name as other `lodash` methods. */ -var nativeKeys = getNative(Object, 'keys'); +},{}],77:[function(require,module,exports){ +/** + * lodash 3.0.9 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used to detect unsigned integer values. */ +var reIsUint = /^\d+$/; /** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) * of an array-like value. */ var MAX_SAFE_INTEGER = 9007199254740991; @@ -12796,44 +12802,39 @@ function isIndex(value, length) { } /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * Checks if the provided arguments are from an iteratee call. * * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. */ -function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object)) { + var other = object[index]; + return value === value ? (value === other) : (other !== other); + } + return false; } /** - * A fallback implementation of `Object.keys` which creates an array of the - * own enumerable property names of `object`. + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). * * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ -function shimKeys(object) { - var props = keysIn(object), - propsLength = props.length, - length = propsLength && object.length; - - var allowIndexes = !!length && isLength(length) && - (isArray(object) || isArguments(object)); - - var index = -1, - result = []; - - while (++index < propsLength) { - var key = props[index]; - if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { - result.push(key); - } - } - return result; + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; } /** @@ -12863,96 +12864,9 @@ function isObject(value) { return !!value && (type == 'object' || type == 'function'); } -/** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) - * for more details. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ -var keys = !nativeKeys ? shimKeys : function(object) { - var Ctor = object == null ? undefined : object.constructor; - if ((typeof Ctor == 'function' && Ctor.prototype === object) || - (typeof object != 'function' && isArrayLike(object))) { - return shimKeys(object); - } - return isObject(object) ? nativeKeys(object) : []; -}; - -/** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ -function keysIn(object) { - if (object == null) { - return []; - } - if (!isObject(object)) { - object = Object(object); - } - var length = object.length; - length = (length && isLength(length) && - (isArray(object) || isArguments(object)) && length) || 0; - - var Ctor = object.constructor, - index = -1, - isProto = typeof Ctor == 'function' && Ctor.prototype === object, - result = Array(length), - skipIndexes = length > 0; - - while (++index < length) { - result[index] = (index + ''); - } - for (var key in object) { - if (!(skipIndexes && isIndex(key, length)) && - !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; -} - -module.exports = keys; +module.exports = isIterateeCall; -},{"lodash._getnative":73,"lodash.isarguments":76,"lodash.isarray":77}],79:[function(require,module,exports){ +},{}],78:[function(require,module,exports){ (function (process){ var path = require('path'); var fs = require('fs'); @@ -13054,7 +12968,7 @@ mkdirP.sync = function sync (p, opts, made) { }; }).call(this,require('_process')) -},{"_process":82,"fs":42,"path":42}],80:[function(require,module,exports){ +},{"_process":81,"fs":42,"path":42}],79:[function(require,module,exports){ exports.endianness = function () { return 'LE' }; exports.hostname = function () { @@ -13101,7 +13015,7 @@ exports.tmpdir = exports.tmpDir = function () { exports.EOL = '\n'; -},{}],81:[function(require,module,exports){ +},{}],80:[function(require,module,exports){ (function (process){ 'use strict'; @@ -13148,7 +13062,7 @@ function nextTick(fn, arg1, arg2, arg3) { } }).call(this,require('_process')) -},{"_process":82}],82:[function(require,module,exports){ +},{"_process":81}],81:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -13319,6 +13233,10 @@ process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } process.binding = function (name) { throw new Error('process.binding is not supported'); @@ -13330,10 +13248,10 @@ process.chdir = function (dir) { }; process.umask = function() { return 0; }; -},{}],83:[function(require,module,exports){ -module.exports = require("./lib/_stream_duplex.js") +},{}],82:[function(require,module,exports){ +module.exports = require('./lib/_stream_duplex.js'); -},{"./lib/_stream_duplex.js":84}],84:[function(require,module,exports){ +},{"./lib/_stream_duplex.js":83}],83:[function(require,module,exports){ // a duplex stream is just a stream that is both readable and writable. // Since JS doesn't have multiple prototypal inheritance, this class // prototypally inherits from Readable, and then parasitically from @@ -13409,7 +13327,7 @@ function forEach(xs, f) { f(xs[i], i); } } -},{"./_stream_readable":86,"./_stream_writable":88,"core-util-is":45,"inherits":66,"process-nextick-args":81}],85:[function(require,module,exports){ +},{"./_stream_readable":85,"./_stream_writable":87,"core-util-is":44,"inherits":65,"process-nextick-args":80}],84:[function(require,module,exports){ // a passthrough stream. // basically just the most minimal sort of Transform stream. // Every written chunk gets output as-is. @@ -13436,7 +13354,7 @@ function PassThrough(options) { PassThrough.prototype._transform = function (chunk, encoding, cb) { cb(null, chunk); }; -},{"./_stream_transform":87,"core-util-is":45,"inherits":66}],86:[function(require,module,exports){ +},{"./_stream_transform":86,"core-util-is":44,"inherits":65}],85:[function(require,module,exports){ (function (process){ 'use strict'; @@ -13450,6 +13368,10 @@ var processNextTick = require('process-nextick-args'); var isArray = require('isarray'); /**/ +/**/ +var Duplex; +/**/ + Readable.ReadableState = ReadableState; /**/ @@ -13461,19 +13383,11 @@ var EElistenerCount = function (emitter, type) { /**/ /**/ -var Stream; -(function () { - try { - Stream = require('st' + 'ream'); - } catch (_) {} finally { - if (!Stream) Stream = require('events').EventEmitter; - } -})(); +var Stream = require('./internal/streams/stream'); /**/ -var Buffer = require('buffer').Buffer; /**/ -var bufferShim = require('buffer-shims'); +var Buffer = require('safe-buffer').Buffer; /**/ /**/ @@ -13496,7 +13410,11 @@ var StringDecoder; util.inherits(Readable, Stream); +var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; + function prependListener(emitter, event, fn) { + // Sadly this is not cacheable as some libraries bundle their own + // event emitter implementation with them. if (typeof emitter.prependListener === 'function') { return emitter.prependListener(event, fn); } else { @@ -13508,7 +13426,6 @@ function prependListener(emitter, event, fn) { } } -var Duplex; function ReadableState(options, stream) { Duplex = Duplex || require('./_stream_duplex'); @@ -13527,7 +13444,7 @@ function ReadableState(options, stream) { this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; // cast to ints. - this.highWaterMark = ~ ~this.highWaterMark; + this.highWaterMark = ~~this.highWaterMark; // A linked list is used to store data chunks instead of an array because the // linked list can remove elements from the beginning faster than @@ -13578,7 +13495,6 @@ function ReadableState(options, stream) { } } -var Duplex; function Readable(options) { Duplex = Duplex || require('./_stream_duplex'); @@ -13604,7 +13520,7 @@ Readable.prototype.push = function (chunk, encoding) { if (!state.objectMode && typeof chunk === 'string') { encoding = encoding || state.defaultEncoding; if (encoding !== state.encoding) { - chunk = bufferShim.from(chunk, encoding); + chunk = Buffer.from(chunk, encoding); encoding = ''; } } @@ -13901,7 +13817,7 @@ function maybeReadMore_(stream, state) { // for virtual (non-string, non-buffer) streams, "length" is somewhat // arbitrary, and perhaps not very meaningful. Readable.prototype._read = function (n) { - this.emit('error', new Error('not implemented')); + this.emit('error', new Error('_read() is not implemented')); }; Readable.prototype.pipe = function (dest, pipeOpts) { @@ -13924,7 +13840,7 @@ Readable.prototype.pipe = function (dest, pipeOpts) { var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; - var endFn = doEnd ? onend : cleanup; + var endFn = doEnd ? onend : unpipe; if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn); dest.on('unpipe', onunpipe); @@ -13957,7 +13873,7 @@ Readable.prototype.pipe = function (dest, pipeOpts) { dest.removeListener('error', onerror); dest.removeListener('unpipe', onunpipe); src.removeListener('end', onend); - src.removeListener('end', cleanup); + src.removeListener('end', unpipe); src.removeListener('data', ondata); cleanedUp = true; @@ -14079,16 +13995,16 @@ Readable.prototype.unpipe = function (dest) { state.pipesCount = 0; state.flowing = false; - for (var _i = 0; _i < len; _i++) { - dests[_i].emit('unpipe', this); + for (var i = 0; i < len; i++) { + dests[i].emit('unpipe', this); }return this; } // try to find the right one. - var i = indexOf(state.pipes, dest); - if (i === -1) return this; + var index = indexOf(state.pipes, dest); + if (index === -1) return this; - state.pipes.splice(i, 1); + state.pipes.splice(index, 1); state.pipesCount -= 1; if (state.pipesCount === 1) state.pipes = state.pipes[0]; @@ -14220,10 +14136,9 @@ Readable.prototype.wrap = function (stream) { } // proxy certain important events. - var events = ['error', 'close', 'destroy', 'pause', 'resume']; - forEach(events, function (ev) { - stream.on(ev, self.emit.bind(self, ev)); - }); + for (var n = 0; n < kProxyEvents.length; n++) { + stream.on(kProxyEvents[n], self.emit.bind(self, kProxyEvents[n])); + } // when we try to consume some more bytes, simply unpause the // underlying stream. @@ -14315,7 +14230,7 @@ function copyFromBufferString(n, list) { // This function is designed to be inlinable, so please take care when making // changes to the function body. function copyFromBuffer(n, list) { - var ret = bufferShim.allocUnsafe(n); + var ret = Buffer.allocUnsafe(n); var p = list.head; var c = 1; p.data.copy(ret); @@ -14376,7 +14291,7 @@ function indexOf(xs, x) { return -1; } }).call(this,require('_process')) -},{"./_stream_duplex":84,"./internal/streams/BufferList":89,"_process":82,"buffer":44,"buffer-shims":43,"core-util-is":45,"events":63,"inherits":66,"isarray":68,"process-nextick-args":81,"string_decoder/":95,"util":40}],87:[function(require,module,exports){ +},{"./_stream_duplex":83,"./internal/streams/BufferList":88,"./internal/streams/stream":89,"_process":81,"core-util-is":44,"events":62,"inherits":65,"isarray":67,"process-nextick-args":80,"safe-buffer":94,"string_decoder/":96,"util":40}],86:[function(require,module,exports){ // a transform stream is a readable/writable stream where you do // something with the data. Sometimes it's called a "filter", // but that's not a great name for it, since that implies a thing where @@ -14473,7 +14388,6 @@ function Transform(options) { this._transformState = new TransformState(this); - // when the writable side finishes, then flush out anything remaining. var stream = this; // start out asking for a readable event once data is transformed. @@ -14490,9 +14404,10 @@ function Transform(options) { if (typeof options.flush === 'function') this._flush = options.flush; } + // When the writable side finishes, then flush out anything remaining. this.once('prefinish', function () { - if (typeof this._flush === 'function') this._flush(function (er) { - done(stream, er); + if (typeof this._flush === 'function') this._flush(function (er, data) { + done(stream, er, data); });else done(stream); }); } @@ -14513,7 +14428,7 @@ Transform.prototype.push = function (chunk, encoding) { // an error, then that'll put the hurt on the whole operation. If you // never call cb(), then you'll never get another chunk. Transform.prototype._transform = function (chunk, encoding, cb) { - throw new Error('Not implemented'); + throw new Error('_transform() is not implemented'); }; Transform.prototype._write = function (chunk, encoding, cb) { @@ -14543,9 +14458,11 @@ Transform.prototype._read = function (n) { } }; -function done(stream, er) { +function done(stream, er, data) { if (er) return stream.emit('error', er); + if (data !== null && data !== undefined) stream.push(data); + // if there's nothing in the write buffer, then that means // that nothing more will ever be provided var ws = stream._writableState; @@ -14557,7 +14474,7 @@ function done(stream, er) { return stream.push(null); } -},{"./_stream_duplex":84,"core-util-is":45,"inherits":66}],88:[function(require,module,exports){ +},{"./_stream_duplex":83,"core-util-is":44,"inherits":65}],87:[function(require,module,exports){ (function (process){ // A bit simpler than readable streams. // Implement an async ._write(chunk, encoding, cb), and it'll handle all @@ -14575,6 +14492,10 @@ var processNextTick = require('process-nextick-args'); var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick; /**/ +/**/ +var Duplex; +/**/ + Writable.WritableState = WritableState; /**/ @@ -14589,19 +14510,11 @@ var internalUtil = { /**/ /**/ -var Stream; -(function () { - try { - Stream = require('st' + 'ream'); - } catch (_) {} finally { - if (!Stream) Stream = require('events').EventEmitter; - } -})(); +var Stream = require('./internal/streams/stream'); /**/ -var Buffer = require('buffer').Buffer; /**/ -var bufferShim = require('buffer-shims'); +var Buffer = require('safe-buffer').Buffer; /**/ util.inherits(Writable, Stream); @@ -14615,7 +14528,6 @@ function WriteReq(chunk, encoding, cb) { this.next = null; } -var Duplex; function WritableState(options, stream) { Duplex = Duplex || require('./_stream_duplex'); @@ -14635,8 +14547,9 @@ function WritableState(options, stream) { this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; // cast to ints. - this.highWaterMark = ~ ~this.highWaterMark; + this.highWaterMark = ~~this.highWaterMark; + // drain event flag. this.needDrain = false; // at the start of calling end() this.ending = false; @@ -14711,7 +14624,7 @@ function WritableState(options, stream) { this.corkedRequestsFree = new CorkedRequest(this); } -WritableState.prototype.getBuffer = function writableStateGetBuffer() { +WritableState.prototype.getBuffer = function getBuffer() { var current = this.bufferedRequest; var out = []; while (current) { @@ -14731,13 +14644,37 @@ WritableState.prototype.getBuffer = function writableStateGetBuffer() { } catch (_) {} })(); -var Duplex; +// Test _writableState for inheritance to account for Duplex streams, +// whose prototype chain only points to Readable. +var realHasInstance; +if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { + realHasInstance = Function.prototype[Symbol.hasInstance]; + Object.defineProperty(Writable, Symbol.hasInstance, { + value: function (object) { + if (realHasInstance.call(this, object)) return true; + + return object && object._writableState instanceof WritableState; + } + }); +} else { + realHasInstance = function (object) { + return object instanceof this; + }; +} + function Writable(options) { Duplex = Duplex || require('./_stream_duplex'); - // Writable ctor is applied to Duplexes, though they're not - // instanceof Writable, they're instanceof Readable. - if (!(this instanceof Writable) && !(this instanceof Duplex)) return new Writable(options); + // Writable ctor is applied to Duplexes, too. + // `realHasInstance` is necessary because using plain `instanceof` + // would return false, as no `_writableState` property is attached. + + // Trying to use the custom `instanceof` for Writable here will also break the + // Node.js LazyTransform implementation, which has a non-trivial getter for + // `_writableState` that would lead to infinite recursion. + if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { + return new Writable(options); + } this._writableState = new WritableState(options, this); @@ -14765,20 +14702,16 @@ function writeAfterEnd(stream, cb) { processNextTick(cb, er); } -// If we get something that is not a buffer, string, null, or undefined, -// and we're not in objectMode, then that's an error. -// Otherwise stream chunks are all considered to be of length=1, and the -// watermarks determine how many objects to keep in the buffer, rather than -// how many bytes or characters. +// Checks that a user-supplied chunk is valid, especially for the particular +// mode the stream is in. Currently this means that `null` is never accepted +// and undefined/non-string values are only allowed in object mode. function validChunk(stream, state, chunk, cb) { var valid = true; var er = false; - // Always throw error if a null is written - // if we are not in object mode then throw - // if it is not a buffer, string, or undefined. + if (chunk === null) { er = new TypeError('May not write null values to stream'); - } else if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { er = new TypeError('Invalid non-string/buffer chunk'); } if (er) { @@ -14792,19 +14725,20 @@ function validChunk(stream, state, chunk, cb) { Writable.prototype.write = function (chunk, encoding, cb) { var state = this._writableState; var ret = false; + var isBuf = Buffer.isBuffer(chunk); if (typeof encoding === 'function') { cb = encoding; encoding = null; } - if (Buffer.isBuffer(chunk)) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; + if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; if (typeof cb !== 'function') cb = nop; - if (state.ended) writeAfterEnd(this, cb);else if (validChunk(this, state, chunk, cb)) { + if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { state.pendingcb++; - ret = writeOrBuffer(this, state, chunk, encoding, cb); + ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); } return ret; @@ -14836,7 +14770,7 @@ Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { function decodeChunk(state, chunk, encoding) { if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { - chunk = bufferShim.from(chunk, encoding); + chunk = Buffer.from(chunk, encoding); } return chunk; } @@ -14844,10 +14778,11 @@ function decodeChunk(state, chunk, encoding) { // if we're already writing something, then just put this // in the queue, and wait our turn. Otherwise, call _write // If we return false, then we need a drain event, so set that flag. -function writeOrBuffer(stream, state, chunk, encoding, cb) { - chunk = decodeChunk(state, chunk, encoding); - - if (Buffer.isBuffer(chunk)) encoding = 'buffer'; +function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { + if (!isBuf) { + chunk = decodeChunk(state, chunk, encoding); + if (Buffer.isBuffer(chunk)) encoding = 'buffer'; + } var len = state.objectMode ? 1 : chunk.length; state.length += len; @@ -14916,8 +14851,8 @@ function onwrite(stream, er) { asyncWrite(afterWrite, stream, state, finished, cb); /**/ } else { - afterWrite(stream, state, finished, cb); - } + afterWrite(stream, state, finished, cb); + } } } @@ -14997,7 +14932,7 @@ function clearBuffer(stream, state) { } Writable.prototype._write = function (chunk, encoding, cb) { - cb(new Error('not implemented')); + cb(new Error('_write() is not implemented')); }; Writable.prototype._writev = null; @@ -15068,7 +15003,6 @@ function CorkedRequest(state) { this.next = null; this.entry = null; - this.finish = function (err) { var entry = _this.entry; _this.entry = null; @@ -15086,12 +15020,12 @@ function CorkedRequest(state) { }; } }).call(this,require('_process')) -},{"./_stream_duplex":84,"_process":82,"buffer":44,"buffer-shims":43,"core-util-is":45,"events":63,"inherits":66,"process-nextick-args":81,"util-deprecate":96}],89:[function(require,module,exports){ +},{"./_stream_duplex":83,"./internal/streams/stream":89,"_process":81,"core-util-is":44,"inherits":65,"process-nextick-args":80,"safe-buffer":94,"util-deprecate":98}],88:[function(require,module,exports){ 'use strict'; -var Buffer = require('buffer').Buffer; /**/ -var bufferShim = require('buffer-shims'); + +var Buffer = require('safe-buffer').Buffer; /**/ module.exports = BufferList; @@ -15139,9 +15073,9 @@ BufferList.prototype.join = function (s) { }; BufferList.prototype.concat = function (n) { - if (this.length === 0) return bufferShim.alloc(0); + if (this.length === 0) return Buffer.alloc(0); if (this.length === 1) return this.head.data; - var ret = bufferShim.allocUnsafe(n >>> 0); + var ret = Buffer.allocUnsafe(n >>> 0); var p = this.head; var i = 0; while (p) { @@ -15151,36 +15085,31 @@ BufferList.prototype.concat = function (n) { } return ret; }; -},{"buffer":44,"buffer-shims":43}],90:[function(require,module,exports){ -module.exports = require("./lib/_stream_passthrough.js") +},{"safe-buffer":94}],89:[function(require,module,exports){ +module.exports = require('events').EventEmitter; -},{"./lib/_stream_passthrough.js":85}],91:[function(require,module,exports){ -(function (process){ -var Stream = (function (){ - try { - return require('st' + 'ream'); // hack to fix a circular dependency issue when used with browserify - } catch(_){} -}()); +},{"events":62}],90:[function(require,module,exports){ +module.exports = require('./readable').PassThrough + +},{"./readable":91}],91:[function(require,module,exports){ exports = module.exports = require('./lib/_stream_readable.js'); -exports.Stream = Stream || exports; +exports.Stream = exports; exports.Readable = exports; exports.Writable = require('./lib/_stream_writable.js'); exports.Duplex = require('./lib/_stream_duplex.js'); exports.Transform = require('./lib/_stream_transform.js'); exports.PassThrough = require('./lib/_stream_passthrough.js'); -if (!process.browser && process.env.READABLE_STREAM === 'disable' && Stream) { - module.exports = Stream; -} +},{"./lib/_stream_duplex.js":83,"./lib/_stream_passthrough.js":84,"./lib/_stream_readable.js":85,"./lib/_stream_transform.js":86,"./lib/_stream_writable.js":87}],92:[function(require,module,exports){ +module.exports = require('./readable').Transform -}).call(this,require('_process')) -},{"./lib/_stream_duplex.js":84,"./lib/_stream_passthrough.js":85,"./lib/_stream_readable.js":86,"./lib/_stream_transform.js":87,"./lib/_stream_writable.js":88,"_process":82}],92:[function(require,module,exports){ -module.exports = require("./lib/_stream_transform.js") +},{"./readable":91}],93:[function(require,module,exports){ +module.exports = require('./lib/_stream_writable.js'); -},{"./lib/_stream_transform.js":87}],93:[function(require,module,exports){ -module.exports = require("./lib/_stream_writable.js") +},{"./lib/_stream_writable.js":87}],94:[function(require,module,exports){ +module.exports = require('buffer') -},{"./lib/_stream_writable.js":88}],94:[function(require,module,exports){ +},{"buffer":43}],95:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -15309,230 +15238,344 @@ Stream.prototype.pipe = function(dest, options) { return dest; }; -},{"events":63,"inherits":66,"readable-stream/duplex.js":83,"readable-stream/passthrough.js":90,"readable-stream/readable.js":91,"readable-stream/transform.js":92,"readable-stream/writable.js":93}],95:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var Buffer = require('buffer').Buffer; +},{"events":62,"inherits":65,"readable-stream/duplex.js":82,"readable-stream/passthrough.js":90,"readable-stream/readable.js":91,"readable-stream/transform.js":92,"readable-stream/writable.js":93}],96:[function(require,module,exports){ +'use strict'; -var isBufferEncoding = Buffer.isEncoding - || function(encoding) { - switch (encoding && encoding.toLowerCase()) { - case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true; - default: return false; - } - } +var Buffer = require('safe-buffer').Buffer; +var isEncoding = Buffer.isEncoding || function (encoding) { + encoding = '' + encoding; + switch (encoding && encoding.toLowerCase()) { + case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': + return true; + default: + return false; + } +}; -function assertEncoding(encoding) { - if (encoding && !isBufferEncoding(encoding)) { - throw new Error('Unknown encoding: ' + encoding); +function _normalizeEncoding(enc) { + if (!enc) return 'utf8'; + var retried; + while (true) { + switch (enc) { + case 'utf8': + case 'utf-8': + return 'utf8'; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return 'utf16le'; + case 'latin1': + case 'binary': + return 'latin1'; + case 'base64': + case 'ascii': + case 'hex': + return enc; + default: + if (retried) return; // undefined + enc = ('' + enc).toLowerCase(); + retried = true; + } } +}; + +// Do not cache `Buffer.isEncoding` when checking encoding names as some +// modules monkey-patch it to support additional encodings +function normalizeEncoding(enc) { + var nenc = _normalizeEncoding(enc); + if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); + return nenc || enc; } // StringDecoder provides an interface for efficiently splitting a series of // buffers into a series of JS strings without breaking apart multi-byte -// characters. CESU-8 is handled as part of the UTF-8 encoding. -// -// @TODO Handling all encodings inside a single object makes it very difficult -// to reason about this code, so it should be split up in the future. -// @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code -// points as used by CESU-8. -var StringDecoder = exports.StringDecoder = function(encoding) { - this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); - assertEncoding(encoding); +// characters. +exports.StringDecoder = StringDecoder; +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + var nb; switch (this.encoding) { - case 'utf8': - // CESU-8 represents each of Surrogate Pair by 3-bytes - this.surrogateSize = 3; - break; - case 'ucs2': case 'utf16le': - // UTF-16 represents each of Surrogate Pair by 2-bytes - this.surrogateSize = 2; - this.detectIncompleteChar = utf16DetectIncompleteChar; + this.text = utf16Text; + this.end = utf16End; + nb = 4; + break; + case 'utf8': + this.fillLast = utf8FillLast; + nb = 4; break; case 'base64': - // Base-64 stores 3 bytes in 4 chars, and pads the remainder. - this.surrogateSize = 3; - this.detectIncompleteChar = base64DetectIncompleteChar; + this.text = base64Text; + this.end = base64End; + nb = 3; break; default: - this.write = passThroughWrite; + this.write = simpleWrite; + this.end = simpleEnd; return; } + this.lastNeed = 0; + this.lastTotal = 0; + this.lastChar = Buffer.allocUnsafe(nb); +} - // Enough space to store all bytes of a single character. UTF-8 needs 4 - // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). - this.charBuffer = new Buffer(6); - // Number of bytes received for the current incomplete multi-byte character. - this.charReceived = 0; - // Number of bytes expected for the current incomplete multi-byte character. - this.charLength = 0; +StringDecoder.prototype.write = function (buf) { + if (buf.length === 0) return ''; + var r; + var i; + if (this.lastNeed) { + r = this.fillLast(buf); + if (r === undefined) return ''; + i = this.lastNeed; + this.lastNeed = 0; + } else { + i = 0; + } + if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); + return r || ''; }; +StringDecoder.prototype.end = utf8End; -// write decodes the given buffer and returns it as JS string that is -// guaranteed to not contain any partial multi-byte characters. Any partial -// character found at the end of the buffer is buffered up, and will be -// returned when calling write again with the remaining bytes. -// -// Note: Converting a Buffer containing an orphan surrogate to a String -// currently works, but converting a String to a Buffer (via `new Buffer`, or -// Buffer#write) will replace incomplete surrogates with the unicode -// replacement character. See https://codereview.chromium.org/121173009/ . -StringDecoder.prototype.write = function(buffer) { - var charStr = ''; - // if our last write ended with an incomplete multibyte character - while (this.charLength) { - // determine how many remaining bytes this buffer has to offer for this char - var available = (buffer.length >= this.charLength - this.charReceived) ? - this.charLength - this.charReceived : - buffer.length; - - // add the new bytes to the char buffer - buffer.copy(this.charBuffer, this.charReceived, 0, available); - this.charReceived += available; - - if (this.charReceived < this.charLength) { - // still not enough chars in this buffer? wait for more ... - return ''; - } - - // remove bytes belonging to the current character from the buffer - buffer = buffer.slice(available, buffer.length); - - // get the character that was split - charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); - - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - var charCode = charStr.charCodeAt(charStr.length - 1); - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - this.charLength += this.surrogateSize; - charStr = ''; - continue; - } - this.charReceived = this.charLength = 0; +// Returns only complete characters in a Buffer +StringDecoder.prototype.text = utf8Text; - // if there are no more bytes in this buffer, just emit our char - if (buffer.length === 0) { - return charStr; - } - break; +// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer +StringDecoder.prototype.fillLast = function (buf) { + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); } + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); + this.lastNeed -= buf.length; +}; - // determine and set charLength / charReceived - this.detectIncompleteChar(buffer); +// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a +// continuation byte. +function utf8CheckByte(byte) { + if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; + return -1; +} - var end = buffer.length; - if (this.charLength) { - // buffer the incomplete character bytes we got - buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); - end -= this.charReceived; +// Checks at most 3 bytes at the end of a Buffer in order to detect an +// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) +// needed to complete the UTF-8 character (if applicable) are returned. +function utf8CheckIncomplete(self, buf, i) { + var j = buf.length - 1; + if (j < i) return 0; + var nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 1; + return nb; } + if (--j < i) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 2; + return nb; + } + if (--j < i) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) { + if (nb === 2) nb = 0;else self.lastNeed = nb - 3; + } + return nb; + } + return 0; +} - charStr += buffer.toString(this.encoding, 0, end); - - var end = charStr.length - 1; - var charCode = charStr.charCodeAt(end); - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - var size = this.surrogateSize; - this.charLength += size; - this.charReceived += size; - this.charBuffer.copy(this.charBuffer, size, 0, size); - buffer.copy(this.charBuffer, 0, 0, size); - return charStr.substring(0, end); +// Validates as many continuation bytes for a multi-byte UTF-8 character as +// needed or are available. If we see a non-continuation byte where we expect +// one, we "replace" the validated continuation bytes we've seen so far with +// UTF-8 replacement characters ('\ufffd'), to match v8's UTF-8 decoding +// behavior. The continuation byte check is included three times in the case +// where all of the continuation bytes for a character exist in the same buffer. +// It is also done this way as a slight performance increase instead of using a +// loop. +function utf8CheckExtraBytes(self, buf, p) { + if ((buf[0] & 0xC0) !== 0x80) { + self.lastNeed = 0; + return '\ufffd'.repeat(p); + } + if (self.lastNeed > 1 && buf.length > 1) { + if ((buf[1] & 0xC0) !== 0x80) { + self.lastNeed = 1; + return '\ufffd'.repeat(p + 1); + } + if (self.lastNeed > 2 && buf.length > 2) { + if ((buf[2] & 0xC0) !== 0x80) { + self.lastNeed = 2; + return '\ufffd'.repeat(p + 2); + } + } } +} - // or just emit the charStr - return charStr; -}; +// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. +function utf8FillLast(buf) { + var p = this.lastTotal - this.lastNeed; + var r = utf8CheckExtraBytes(this, buf, p); + if (r !== undefined) return r; + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, p, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); + } + buf.copy(this.lastChar, p, 0, buf.length); + this.lastNeed -= buf.length; +} + +// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a +// partial character, the character's bytes are buffered until the required +// number of bytes are available. +function utf8Text(buf, i) { + var total = utf8CheckIncomplete(this, buf, i); + if (!this.lastNeed) return buf.toString('utf8', i); + this.lastTotal = total; + var end = buf.length - (total - this.lastNeed); + buf.copy(this.lastChar, 0, end); + return buf.toString('utf8', i, end); +} + +// For UTF-8, a replacement character for each buffered byte of a (partial) +// character needs to be added to the output. +function utf8End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + '\ufffd'.repeat(this.lastTotal - this.lastNeed); + return r; +} + +// UTF-16LE typically needs two bytes per character, but even if we have an even +// number of bytes available, we need to check if we end on a leading/high +// surrogate. In that case, we need to wait for the next two bytes in order to +// decode the last character properly. +function utf16Text(buf, i) { + if ((buf.length - i) % 2 === 0) { + var r = buf.toString('utf16le', i); + if (r) { + var c = r.charCodeAt(r.length - 1); + if (c >= 0xD800 && c <= 0xDBFF) { + this.lastNeed = 2; + this.lastTotal = 4; + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + return r.slice(0, -1); + } + } + return r; + } + this.lastNeed = 1; + this.lastTotal = 2; + this.lastChar[0] = buf[buf.length - 1]; + return buf.toString('utf16le', i, buf.length - 1); +} -// detectIncompleteChar determines if there is an incomplete UTF-8 character at -// the end of the given buffer. If so, it sets this.charLength to the byte -// length that character, and sets this.charReceived to the number of bytes -// that are available for this character. -StringDecoder.prototype.detectIncompleteChar = function(buffer) { - // determine how many bytes we have to check at the end of this buffer - var i = (buffer.length >= 3) ? 3 : buffer.length; +// For UTF-16LE we do not explicitly append special replacement characters if we +// end on a partial character, we simply let v8 handle that. +function utf16End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) { + var end = this.lastTotal - this.lastNeed; + return r + this.lastChar.toString('utf16le', 0, end); + } + return r; +} - // Figure out if one of the last i bytes of our buffer announces an - // incomplete char. - for (; i > 0; i--) { - var c = buffer[buffer.length - i]; +function base64Text(buf, i) { + var n = (buf.length - i) % 3; + if (n === 0) return buf.toString('base64', i); + this.lastNeed = 3 - n; + this.lastTotal = 3; + if (n === 1) { + this.lastChar[0] = buf[buf.length - 1]; + } else { + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + } + return buf.toString('base64', i, buf.length - n); +} - // See http://en.wikipedia.org/wiki/UTF-8#Description +function base64End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); + return r; +} - // 110XXXXX - if (i == 1 && c >> 5 == 0x06) { - this.charLength = 2; - break; - } +// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) +function simpleWrite(buf) { + return buf.toString(this.encoding); +} - // 1110XXXX - if (i <= 2 && c >> 4 == 0x0E) { - this.charLength = 3; - break; - } +function simpleEnd(buf) { + return buf && buf.length ? this.write(buf) : ''; +} +},{"safe-buffer":97}],97:[function(require,module,exports){ +/* eslint-disable node/no-deprecated-api */ +var buffer = require('buffer') +var Buffer = buffer.Buffer - // 11110XXX - if (i <= 3 && c >> 3 == 0x1E) { - this.charLength = 4; - break; - } +// alternative to using Object.keys for old browsers +function copyProps (src, dst) { + for (var key in src) { + dst[key] = src[key] } - this.charReceived = i; -}; +} +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { + module.exports = buffer +} else { + // Copy properties from require('buffer') + copyProps(buffer, exports) + exports.Buffer = SafeBuffer +} -StringDecoder.prototype.end = function(buffer) { - var res = ''; - if (buffer && buffer.length) - res = this.write(buffer); +function SafeBuffer (arg, encodingOrOffset, length) { + return Buffer(arg, encodingOrOffset, length) +} - if (this.charReceived) { - var cr = this.charReceived; - var buf = this.charBuffer; - var enc = this.encoding; - res += buf.slice(0, cr).toString(enc); - } +// Copy static methods from Buffer +copyProps(Buffer, SafeBuffer) - return res; -}; +SafeBuffer.from = function (arg, encodingOrOffset, length) { + if (typeof arg === 'number') { + throw new TypeError('Argument must not be a number') + } + return Buffer(arg, encodingOrOffset, length) +} -function passThroughWrite(buffer) { - return buffer.toString(this.encoding); +SafeBuffer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + var buf = Buffer(size) + if (fill !== undefined) { + if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + } else { + buf.fill(0) + } + return buf } -function utf16DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 2; - this.charLength = this.charReceived ? 2 : 0; +SafeBuffer.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return Buffer(size) } -function base64DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 3; - this.charLength = this.charReceived ? 3 : 0; +SafeBuffer.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return buffer.SlowBuffer(size) } -},{"buffer":44}],96:[function(require,module,exports){ +},{"buffer":43}],98:[function(require,module,exports){ (function (global){ /** @@ -15603,16 +15646,16 @@ function config (name) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],97:[function(require,module,exports){ -arguments[4][66][0].apply(exports,arguments) -},{"dup":66}],98:[function(require,module,exports){ +},{}],99:[function(require,module,exports){ +arguments[4][65][0].apply(exports,arguments) +},{"dup":65}],100:[function(require,module,exports){ module.exports = function isBuffer(arg) { return arg && typeof arg === 'object' && typeof arg.copy === 'function' && typeof arg.fill === 'function' && typeof arg.readUInt8 === 'function'; } -},{}],99:[function(require,module,exports){ +},{}],101:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -16202,4 +16245,4 @@ function hasOwnProperty(obj, prop) { } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":98,"_process":82,"inherits":97}]},{},[1]); +},{"./support/isBuffer":100,"_process":81,"inherits":99}]},{},[1]); diff --git a/package.json b/package.json index 185eced0f8..e199cee1b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mocha", - "version": "3.4.2", + "version": "3.5.0", "description": "simple, flexible, fun test framework", "keywords": [ "mocha", @@ -309,7 +309,7 @@ "dependencies": { "browser-stdout": "1.3.0", "commander": "2.9.0", - "debug": "2.6.0", + "debug": "2.6.8", "diff": "3.2.0", "escape-string-regexp": "1.0.5", "glob": "7.1.1", @@ -320,10 +320,12 @@ "supports-color": "3.1.2" }, "devDependencies": { + "@coderbyheart/karma-sauce-launcher": "git://github.com/coderbyheart/karma-sauce-launcher#5259942cd6d40090eaa13ceeef5b0b8738c7710f", "assert": "^1.4.1", "browserify": "^13.0.0", "coffee-script": "^1.10.0", "coveralls": "^2.11.15", + "cross-spawn": "^5.1.0", "eslint": "^3.11.1", "eslint-config-semistandard": "^7.0.0", "eslint-config-standard": "^6.2.1", @@ -336,13 +338,14 @@ "karma-chrome-launcher": "^2.0.0", "karma-expect": "^1.1.2", "karma-mocha": "^1.3.0", - "karma-phantomjs-launcher": "^1.0.2", - "karma-sauce-launcher": "coderbyheart/karma-sauce-launcher", + "karma-phantomjs-launcher": "0.2.3", "karma-spec-reporter": "0.0.26", "nyc": "^10.0.0", + "os-name": "^2.0.1", "phantomjs": "1.9.8", + "readable-stream": "2.2.11", "rimraf": "^2.5.2", - "should": "^11.1.1", + "should": "^9.0.2", "through2": "^2.0.1", "watchify": "^3.7.0" }, @@ -368,11 +371,5 @@ "supports-color": false }, "homepage": "https://mochajs.org", - "logo": "https://cldup.com/S9uQ-cOLYz.svg", - "greenkeeper": { - "ignore": [ - "phantomjs", - "lodash.create" - ] - } + "logo": "https://cldup.com/S9uQ-cOLYz.svg" } diff --git a/test/.eslintrc.yaml b/test/.eslintrc.yaml index 1830a0b6f4..a32fd84d48 100644 --- a/test/.eslintrc.yaml +++ b/test/.eslintrc.yaml @@ -3,5 +3,3 @@ env: globals: expect: false assert: false - # https://github.com/sindresorhus/globals/pull/102 - run: false diff --git a/test/browser-fixtures/bdd.fixture.js b/test/browser-fixtures/bdd.fixture.js index d19993676a..5fe802f74a 100644 --- a/test/browser-fixtures/bdd.fixture.js +++ b/test/browser-fixtures/bdd.fixture.js @@ -2,5 +2,7 @@ /* eslint-env browser */ +process.stdout = require('browser-stdout')(); + window.mocha.timeout(200) .ui('bdd'); diff --git a/test/browser-fixtures/exports.fixture.js b/test/browser-fixtures/exports.fixture.js index 97b8b97cbe..a4c25cff99 100644 --- a/test/browser-fixtures/exports.fixture.js +++ b/test/browser-fixtures/exports.fixture.js @@ -2,5 +2,7 @@ /* eslint-env browser */ +process.stdout = require('browser-stdout')(); + window.mocha.timeout(200) .ui('exports'); diff --git a/test/browser-fixtures/qunit.fixture.js b/test/browser-fixtures/qunit.fixture.js index a3fd887940..79b49498d5 100644 --- a/test/browser-fixtures/qunit.fixture.js +++ b/test/browser-fixtures/qunit.fixture.js @@ -2,5 +2,7 @@ /* eslint-env browser */ +process.stdout = require('browser-stdout')(); + window.mocha.timeout(200) .ui('qunit'); diff --git a/test/browser-fixtures/tdd.fixture.js b/test/browser-fixtures/tdd.fixture.js index 0c36f0c54b..2fdc8f758c 100644 --- a/test/browser-fixtures/tdd.fixture.js +++ b/test/browser-fixtures/tdd.fixture.js @@ -2,5 +2,7 @@ /* eslint-env browser */ +process.stdout = require('browser-stdout')(); + window.mocha.timeout(200) .ui('tdd'); diff --git a/test/browser/README.md b/test/browser/README.md new file mode 100644 index 0000000000..15e4178b3e --- /dev/null +++ b/test/browser/README.md @@ -0,0 +1,3 @@ +These files need to be run manually by loading the `.html` file(s) in a browser. + +It would be awesome if we could automate that! diff --git a/test/browser/index.html b/test/browser/index.html index 2331834ecf..d8b7cc9f72 100644 --- a/test/browser/index.html +++ b/test/browser/index.html @@ -11,7 +11,7 @@ if (!expr) throw new Error(msg || 'failed'); } - + diff --git a/test/acceptance/test.coffee b/test/compiler/test.coffee similarity index 100% rename from test/acceptance/test.coffee rename to test/compiler/test.coffee diff --git a/test/acceptance/test.foo b/test/compiler/test.foo similarity index 100% rename from test/acceptance/test.foo rename to test/compiler/test.foo diff --git a/test/acceptance/glob/glob.sh b/test/glob/glob.sh similarity index 84% rename from test/acceptance/glob/glob.sh rename to test/glob/glob.sh index 823ba07fb9..c0cb21d3f8 100755 --- a/test/acceptance/glob/glob.sh +++ b/test/glob/glob.sh @@ -7,7 +7,7 @@ cd $SCRIPT_DIR || { exit 1 } -../../../bin/mocha -R json-stream ./*.js > /tmp/mocha-glob.txt || { +../../bin/mocha -R json-stream ./*.js > /tmp/mocha-glob.txt || { echo Globbing ./*.js in `pwd` failed. exit 1 } @@ -17,7 +17,7 @@ cat /tmp/mocha-glob.txt | grep -q -F '["end",{"suites":1,"tests":1,"passes":1,"p exit 1 } -../../../bin/mocha -R json-stream ./*-none.js 2> /tmp/mocha-glob.txt && { +../../bin/mocha -R json-stream ./*-none.js 2> /tmp/mocha-glob.txt && { echo Globbing './*-none.js' in `pwd` failed. exit 1 } @@ -27,7 +27,7 @@ cat /tmp/mocha-glob.txt | grep -q -F 'Could not find any test files matching pat exit 1 } -../../../bin/mocha -R json-stream ./*.js ./*-none.js >& /tmp/mocha-glob.txt || { +../../bin/mocha -R json-stream ./*.js ./*-none.js >& /tmp/mocha-glob.txt || { echo Globbing ./*.js ./*-none.js in `pwd` failed. exit 1 } @@ -43,7 +43,7 @@ cat /tmp/mocha-glob.txt | grep -q -F 'Could not find any test files matching pat # In windows, the shell passes globs unexpanded, executables do expansion if they support it. # Adding single-quotes around the glob below makes bash pass glob unexpanded, # allowing us to test windows-style globbing in bash. -../../../bin/mocha -R json-stream './*.js' > /tmp/mocha-glob.txt || { +../../bin/mocha -R json-stream './*.js' > /tmp/mocha-glob.txt || { echo Globbing './*.js' in `pwd` failed. exit 1 } @@ -53,7 +53,7 @@ cat /tmp/mocha-glob.txt | grep -q -F '["end",{"suites":1,"tests":1,"passes":1,"p exit 1 } -../../../bin/mocha -R json-stream './*-none.js' 2> /tmp/mocha-glob.txt && { +../../bin/mocha -R json-stream './*-none.js' 2> /tmp/mocha-glob.txt && { echo Globbing './*-none.js' in `pwd` failed. exit 1 } diff --git a/test/acceptance/glob/glob.spec.js b/test/glob/glob.spec.js similarity index 100% rename from test/acceptance/glob/glob.spec.js rename to test/glob/glob.spec.js diff --git a/test/integration/fixtures/options/forbid-only/only.js b/test/integration/fixtures/options/forbid-only/only.js new file mode 100644 index 0000000000..c09e804126 --- /dev/null +++ b/test/integration/fixtures/options/forbid-only/only.js @@ -0,0 +1,7 @@ +'use strict'; + +describe('forbid only - test marked with only', function () { + it('test1', function () {}); + it.only('test2', function () {}); + it('test3', function () {}); +}); diff --git a/test/integration/fixtures/options/forbid-only/passed.js b/test/integration/fixtures/options/forbid-only/passed.js new file mode 100644 index 0000000000..6c4d4ac1d4 --- /dev/null +++ b/test/integration/fixtures/options/forbid-only/passed.js @@ -0,0 +1,7 @@ +'use strict'; + +describe('forbid only - `.only` is not used', function () { + it('test1', function () {}); + it('test2', function () {}); + it('test3', function () {}); +}); diff --git a/test/integration/fixtures/options/forbid-pending/passed.js b/test/integration/fixtures/options/forbid-pending/passed.js new file mode 100644 index 0000000000..cd12668f4d --- /dev/null +++ b/test/integration/fixtures/options/forbid-pending/passed.js @@ -0,0 +1,7 @@ +'use strict'; + +describe('forbid pending - all test pass', function () { + it('test1', function () {}); + it('test2', function () {}); + it('test3', function () {}); +}); diff --git a/test/integration/fixtures/options/forbid-pending/pending.js b/test/integration/fixtures/options/forbid-pending/pending.js new file mode 100644 index 0000000000..96abd0bf47 --- /dev/null +++ b/test/integration/fixtures/options/forbid-pending/pending.js @@ -0,0 +1,7 @@ +'use strict'; + +describe('forbid pending - test without function', function () { + it('test1', function () {}); + it('test2'); + it('test3', function () {}); +}); diff --git a/test/integration/fixtures/options/forbid-pending/skip.js b/test/integration/fixtures/options/forbid-pending/skip.js new file mode 100644 index 0000000000..c6fd31d303 --- /dev/null +++ b/test/integration/fixtures/options/forbid-pending/skip.js @@ -0,0 +1,7 @@ +'use strict'; + +describe('forbid pending - test marked with skip', function () { + it('test1', function () {}); + it.skip('test2', function () {}); + it('test3', function () {}); +}); diff --git a/test/integration/helpers.js b/test/integration/helpers.js index 025770dd6b..f2d9c81192 100644 --- a/test/integration/helpers.js +++ b/test/integration/helpers.js @@ -1,8 +1,7 @@ 'use strict'; -var spawn = require('child_process').spawn; +var spawn = require('cross-spawn').spawn; var path = require('path'); -var fs = require('fs'); var baseReporter = require('../../lib/reporters/base'); module.exports = { @@ -41,47 +40,6 @@ module.exports = { }); }, - /** - * Invokes the mocha binary on the code of the body of the function. - * 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 {function} fixture - * @param {array} args - * @param {function} fn - */ - runMochaFunction: function (fixture, args, fn) { - var path = resolveFixturePath(fixture.name + '.js' || 'tempfile.js'); - args = args || []; - - var fixtureContent = 'var fn = ' + fixture.toString() + '; fn()'; - fs.writeFileSync(path, fixtureContent, 'utf8'); - - function cleanup () { - fs.unlink(path); - fn.apply(this, arguments); - } - - invokeMocha(args.concat(['-C', path]), function (err, res) { - if (err) { - return cleanup(err); - } - - cleanup(null, getSummary(res)); - }); - }, - /** * Invokes the mocha binary for the given fixture using the JSON reporter, * returning the parsed output, as well as exit code. diff --git a/test/integration/hooks.spec.js b/test/integration/hooks.spec.js index ed3c25b2b1..e68aa66b64 100644 --- a/test/integration/hooks.spec.js +++ b/test/integration/hooks.spec.js @@ -10,7 +10,10 @@ describe('hooks', function () { runMocha('cascade.fixture.js', args, function (err, res) { var lines, expected; - assert(!err); + if (err) { + done(err); + return; + } lines = res.output.split(splitRegExp).map(function (line) { return line.trim(); diff --git a/test/integration/only.spec.js b/test/integration/only.spec.js index b37a4b263e..098af6786c 100644 --- a/test/integration/only.spec.js +++ b/test/integration/only.spec.js @@ -7,7 +7,10 @@ describe('.only()', function () { describe('bdd', function () { it('should run only tests that marked as `only`', function (done) { run('options/only/bdd.fixture.js', ['--ui', 'bdd'], function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 11); assert.equal(res.stats.failures, 0); @@ -20,7 +23,10 @@ describe('.only()', function () { describe('tdd', function () { it('should run only tests that marked as `only`', function (done) { run('options/only/tdd.fixture.js', ['--ui', 'tdd'], function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 8); assert.equal(res.stats.failures, 0); @@ -33,7 +39,10 @@ describe('.only()', function () { describe('qunit', function () { it('should run only tests that marked as `only`', function (done) { run('options/only/qunit.fixture.js', ['--ui', 'qunit'], function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 5); assert.equal(res.stats.failures, 0); diff --git a/test/integration/options.spec.js b/test/integration/options.spec.js index 7c7a3cc75e..be4abf53c5 100644 --- a/test/integration/options.spec.js +++ b/test/integration/options.spec.js @@ -12,7 +12,10 @@ describe('options', function () { it('should fail synchronous specs', function (done) { run('options/async-only-sync.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 1); @@ -25,7 +28,10 @@ describe('options', function () { it('should allow asynchronous specs', function (done) { run('options/async-only-async.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 1); assert.equal(res.stats.failures, 0); @@ -44,7 +50,10 @@ describe('options', function () { it('should stop after the first error', function (done) { run('options/bail.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 1); assert.equal(res.stats.failures, 1); @@ -64,7 +73,10 @@ describe('options', function () { it('should sort tests in alphabetical order', function (done) { run('options/sort*', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 2); assert.equal(res.stats.failures, 0); @@ -84,7 +96,10 @@ describe('options', function () { it('should run the generated test suite', function (done) { run('options/delay.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 1); assert.equal(res.stats.failures, 0); @@ -98,7 +113,10 @@ describe('options', function () { it('should throw an error if the test suite failed to run', function (done) { run('options/delay-fail.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 1); @@ -115,7 +133,10 @@ describe('options', function () { it('runs specs matching a string', function (done) { args = ['--grep', 'match']; run('options/grep.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 2); assert.equal(res.stats.failures, 0); @@ -128,7 +149,10 @@ describe('options', function () { it('with RegExp like strings(pattern follow by flag)', function (done) { args = ['--grep', '/match/i']; run('options/grep.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 4); assert.equal(res.stats.failures, 0); @@ -140,7 +164,10 @@ describe('options', function () { it('string as pattern', function (done) { args = ['--grep', '.*']; run('options/grep.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 4); assert.equal(res.stats.failures, 1); @@ -154,7 +181,10 @@ describe('options', function () { it('runs specs that do not match the pattern', function (done) { args = ['--grep', 'fail', '--invert']; run('options/grep.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 4); assert.equal(res.stats.failures, 0); @@ -169,7 +199,10 @@ describe('options', function () { it('retries after a certain threshold', function (done) { args = ['--retries', '3']; run('options/retries.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); assert.equal(res.stats.tests, 1); @@ -180,4 +213,71 @@ describe('options', function () { }); }); }); + + describe('--forbid-only', function () { + before(function () { + args = ['--forbid-only']; + }); + + it('succeeds if there are only passed tests', function (done) { + run('options/forbid-only/passed.js', args, function (err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.code, 0); + done(); + }); + }); + + it('fails if there are tests marked only', function (done) { + run('options/forbid-only/only.js', args, function (err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.code, 1); + done(); + }); + }); + }); + + describe('--forbid-pending', function () { + before(function () { + args = ['--forbid-pending']; + }); + + it('succeeds if there are only passed tests', function (done) { + run('options/forbid-pending/passed.js', args, function (err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.code, 0); + done(); + }); + }); + + it('fails if there are tests marked skip', function (done) { + run('options/forbid-pending/skip.js', args, function (err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.code, 1); + done(); + }); + }); + + it('fails if there are pending tests', function (done) { + run('options/forbid-pending/pending.js', args, function (err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.code, 1); + done(); + }); + }); + }); }); diff --git a/test/integration/pending.spec.js b/test/integration/pending.spec.js index 19ae30ad3a..f5a400f089 100644 --- a/test/integration/pending.spec.js +++ b/test/integration/pending.spec.js @@ -8,7 +8,10 @@ describe('pending', function () { describe('pending specs', function () { it('should be created by omitting a function', function (done) { run('pending/spec.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 1); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 0); @@ -22,7 +25,10 @@ describe('pending', function () { describe('in spec', function () { it('should immediately skip the spec and run all others', function (done) { run('pending/skip-sync-spec.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 1); assert.equal(res.stats.passes, 1); assert.equal(res.stats.failures, 0); @@ -35,7 +41,10 @@ describe('pending', function () { describe('in before', function () { it('should skip all suite specs', function (done) { run('pending/skip-sync-before.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 2); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 0); @@ -48,7 +57,10 @@ describe('pending', function () { describe('in beforeEach', function () { it('should skip all suite specs', function (done) { run('pending/skip-sync-beforeEach.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 2); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 0); @@ -63,7 +75,10 @@ describe('pending', function () { describe('in spec', function () { it('should immediately skip the spec and run all others', function (done) { run('pending/skip-async-spec.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 1); assert.equal(res.stats.passes, 1); assert.equal(res.stats.failures, 0); @@ -76,7 +91,10 @@ describe('pending', function () { describe('in before', function () { it('should skip all suite specs', function (done) { run('pending/skip-async-before.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 2); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 0); @@ -89,7 +107,10 @@ describe('pending', function () { describe('in beforeEach', function () { it('should skip all suite specs', function (done) { run('pending/skip-sync-beforeEach.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 2); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 0); diff --git a/test/integration/regression.spec.js b/test/integration/regression.spec.js index 74f32f8081..14a1a164f3 100644 --- a/test/integration/regression.spec.js +++ b/test/integration/regression.spec.js @@ -15,7 +15,10 @@ describe('regressions', function () { return (res.output.match(pattern) || []).length; }; - assert(!err); + if (err) { + done(err); + return; + } assert.equal(occurences('testbody1'), 1); assert.equal(occurences('testbody2'), 1); assert.equal(occurences('testbody3'), 1); @@ -36,7 +39,10 @@ describe('regressions', function () { var simpleUiPath = path.join(__dirname, 'fixtures', 'regression', '1794', 'simple-ui.js'); var args = ['--require', simpleUiPath, '--ui', 'simple-ui']; run('regression/1794/issue-1794.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.code, 0, 'Custom UI should be loaded'); done(); }); @@ -47,7 +53,10 @@ describe('regressions', function () { // Could easily take longer on even weaker machines (Travis-CI containers for example). this.timeout(120000); run('regression/issue-1991.fixture.js', [], function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(/process out of memory/.test(res.output), false, 'fixture\'s process out of memory!'); assert.equal(res.code, 0, 'Runnable fn (it/before[Each]/after[Each]) references should be deleted to avoid memory leaks'); done(); @@ -68,7 +77,10 @@ describe('regressions', function () { it('issue-2315: cannot read property currentRetry of undefined', function (done) { runJSON('regression/issue-2315.fixture.js', [], function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 1); @@ -80,7 +92,10 @@ describe('regressions', function () { it('issue-2406: should run nested describe.only suites', function (done) { this.timeout(2000); runJSON('regression/issue-2406.fixture.js', [], function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 2); assert.equal(res.stats.failures, 0); @@ -89,19 +104,26 @@ describe('regressions', function () { }); }); - it('issue-2417: should not recurse infinitely with .only suites nested within each other', function () { + it('issue-2417: should not recurse infinitely with .only suites nested within each other', function (done) { runJSON('regression/issue-2417.fixture.js', [], function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 1); assert.equal(res.stats.failures, 0); assert.equal(res.code, 0); + done(); }); }); it('issue-1417 uncaught exceptions from async specs', function (done) { runJSON('regression/issue-1417.fixture.js', [], function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 2); diff --git a/test/integration/reporters.spec.js b/test/integration/reporters.spec.js index 19b4d8e30c..9bf8df289c 100644 --- a/test/integration/reporters.spec.js +++ b/test/integration/reporters.spec.js @@ -68,7 +68,10 @@ describe('reporters', function () { var args = ['--reporter=' + reporterAtARelativePath]; run('passing.fixture.js', args, function (err, result) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(result.code, 0); done(); }); @@ -81,7 +84,10 @@ describe('reporters', function () { var args = ['--reporter=' + reporterAtAnAbsolutePath]; run('passing.fixture.js', args, function (err, result) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(result.code, 0); done(); }); diff --git a/test/integration/retries.spec.js b/test/integration/retries.spec.js index 9d9301ad78..6197c43ca8 100644 --- a/test/integration/retries.spec.js +++ b/test/integration/retries.spec.js @@ -10,7 +10,10 @@ describe('retries', function () { helpers.runMocha('retries/hooks.fixture.js', args, function (err, res) { var lines, expected; - assert(!err); + if (err) { + done(err); + return; + } lines = res.output.split(helpers.splitRegExp).map(function (line) { return line.trim(); @@ -49,7 +52,10 @@ describe('retries', function () { it('should exit early if test passes', function (done) { helpers.runMochaJSON('retries/early-pass.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.passes, 1); assert.equal(res.stats.failures, 0); assert.equal(res.tests[0].currentRetry, 1); @@ -61,7 +67,10 @@ describe('retries', function () { it('should let test override', function (done) { helpers.runMochaJSON('retries/nested.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 1); assert.equal(res.stats.tests, 1); @@ -75,7 +84,10 @@ describe('retries', function () { helpers.runMocha('retries/async.fixture.js', args, function (err, res) { var lines, expected; - assert(!err); + if (err) { + done(err); + return; + } lines = res.output.split(helpers.splitRegExp).map(function (line) { return line.trim(); diff --git a/test/integration/suite.spec.js b/test/integration/suite.spec.js index f497e72652..4af47697f7 100644 --- a/test/integration/suite.spec.js +++ b/test/integration/suite.spec.js @@ -8,7 +8,10 @@ describe('suite w/no callback', function () { this.timeout(2000); it('should throw a helpful error message when a callback for suite is not supplied', function (done) { run('suite/suite-no-callback.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } var result = res.output.match(/no callback was supplied/) || []; assert.equal(result.length, 1); done(); @@ -20,7 +23,10 @@ describe('skipped suite w/no callback', function () { this.timeout(2000); it('should not throw an error when a callback for skipped suite is not supplied', function (done) { run('suite/suite-skipped-no-callback.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } var pattern = new RegExp('Error', 'g'); var result = res.output.match(pattern) || []; assert.equal(result.length, 0); @@ -33,7 +39,10 @@ describe('skipped suite w/ callback', function () { this.timeout(2000); it('should not throw an error when a callback for skipped suite is supplied', function (done) { run('suite/suite-skipped-callback.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } var pattern = new RegExp('Error', 'g'); var result = res.output.match(pattern) || []; assert.equal(result.length, 0); diff --git a/test/integration/timeout.spec.js b/test/integration/timeout.spec.js index 4e0f989e86..c51ba774de 100644 --- a/test/integration/timeout.spec.js +++ b/test/integration/timeout.spec.js @@ -7,7 +7,10 @@ var args = []; describe('this.timeout()', function () { it('is respected by sync and async suites', function (done) { run('timeout.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 2); diff --git a/test/integration/uncaught.spec.js b/test/integration/uncaught.spec.js index 92e39c195e..9a3dadbbbd 100644 --- a/test/integration/uncaught.spec.js +++ b/test/integration/uncaught.spec.js @@ -7,7 +7,10 @@ var args = []; describe('uncaught exceptions', function () { it('handles uncaught exceptions from hooks', function (done) { run('uncaught-hook.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 1); @@ -21,7 +24,10 @@ describe('uncaught exceptions', function () { it('handles uncaught exceptions from async specs', function (done) { run('uncaught.fixture.js', args, function (err, res) { - assert(!err); + if (err) { + done(err); + return; + } assert.equal(res.stats.pending, 0); assert.equal(res.stats.passes, 0); assert.equal(res.stats.failures, 2); diff --git a/test/acceptance/interfaces/bdd.spec.js b/test/interfaces/bdd.spec.js similarity index 100% rename from test/acceptance/interfaces/bdd.spec.js rename to test/interfaces/bdd.spec.js diff --git a/test/acceptance/interfaces/exports.spec.js b/test/interfaces/exports.spec.js similarity index 100% rename from test/acceptance/interfaces/exports.spec.js rename to test/interfaces/exports.spec.js diff --git a/test/acceptance/interfaces/qunit.spec.js b/test/interfaces/qunit.spec.js similarity index 100% rename from test/acceptance/interfaces/qunit.spec.js rename to test/interfaces/qunit.spec.js diff --git a/test/acceptance/interfaces/tdd.spec.js b/test/interfaces/tdd.spec.js similarity index 100% rename from test/acceptance/interfaces/tdd.spec.js rename to test/interfaces/tdd.spec.js diff --git a/test/jsapi/index.js b/test/jsapi/index.js index 42133578e0..d011c233f3 100644 --- a/test/jsapi/index.js +++ b/test/jsapi/index.js @@ -9,19 +9,18 @@ var mocha = new Mocha({ growl: true }); -// mocha.reporter('spec'); -require('should'); +global.expect = require('expect.js'); -mocha.addFile('test/suite.spec.js'); -mocha.addFile('test/runner.spec.js'); -mocha.addFile('test/runnable.spec.js'); -mocha.addFile('test/hook-sync.spec.js'); -mocha.addFile('test/hook-sync-nested.spec.js'); -mocha.addFile('test/hook-async.spec.js'); -mocha.addFile('test/acceptance/duration.spec.js'); -mocha.addFile('test/acceptance/fs.spec.js'); -mocha.addFile('test/acceptance/globals.spec.js'); -mocha.addFile('test/acceptance/timeout.spec.js'); +mocha.addFile('test/unit/suite.spec.js'); +mocha.addFile('test/unit/runner.spec.js'); +mocha.addFile('test/unit/runnable.spec.js'); +mocha.addFile('test/unit/hook-sync.spec.js'); +mocha.addFile('test/unit/hook-sync-nested.spec.js'); +mocha.addFile('test/unit/hook-async.spec.js'); +mocha.addFile('test/unit/duration.spec.js'); +mocha.addFile('test/node-unit/fs.spec.js'); +mocha.addFile('test/unit/globals.spec.js'); +mocha.addFile('test/unit/timeout.spec.js'); mocha.run(function () { console.log('done'); diff --git a/test/acceptance/misc/exit.spec.js b/test/misc/exit.spec.js similarity index 100% rename from test/acceptance/misc/exit.spec.js rename to test/misc/exit.spec.js diff --git a/test/acceptance/misc/many.spec.js b/test/misc/many.spec.js similarity index 100% rename from test/acceptance/misc/many.spec.js rename to test/misc/many.spec.js diff --git a/test/acceptance/misc/nontty.spec.js b/test/misc/nontty.spec.js similarity index 100% rename from test/acceptance/misc/nontty.spec.js rename to test/misc/nontty.spec.js diff --git a/test/acceptance/misc/only/bdd-require.spec.js b/test/misc/only/bdd-require.spec.js similarity index 90% rename from test/acceptance/misc/only/bdd-require.spec.js rename to test/misc/only/bdd-require.spec.js index 14710c4cd2..1c90d7acda 100644 --- a/test/acceptance/misc/only/bdd-require.spec.js +++ b/test/misc/only/bdd-require.spec.js @@ -2,7 +2,7 @@ /* jshint node: true */ -var mocha = require('../../../../lib/mocha'); +var mocha = require('../../../lib/mocha'); var beforeEach = mocha.beforeEach; var it = mocha.it; diff --git a/test/acceptance/misc/only/bdd.spec.js b/test/misc/only/bdd.spec.js similarity index 100% rename from test/acceptance/misc/only/bdd.spec.js rename to test/misc/only/bdd.spec.js diff --git a/test/acceptance/misc/only/global/bdd.spec.js b/test/misc/only/global/bdd.spec.js similarity index 100% rename from test/acceptance/misc/only/global/bdd.spec.js rename to test/misc/only/global/bdd.spec.js diff --git a/test/acceptance/misc/only/global/qunit.spec.js b/test/misc/only/global/qunit.spec.js similarity index 100% rename from test/acceptance/misc/only/global/qunit.spec.js rename to test/misc/only/global/qunit.spec.js diff --git a/test/acceptance/misc/only/global/tdd.spec.js b/test/misc/only/global/tdd.spec.js similarity index 100% rename from test/acceptance/misc/only/global/tdd.spec.js rename to test/misc/only/global/tdd.spec.js diff --git a/test/acceptance/misc/only/qunit.spec.js b/test/misc/only/qunit.spec.js similarity index 100% rename from test/acceptance/misc/only/qunit.spec.js rename to test/misc/only/qunit.spec.js diff --git a/test/acceptance/misc/only/tdd.spec.js b/test/misc/only/tdd.spec.js similarity index 100% rename from test/acceptance/misc/only/tdd.spec.js rename to test/misc/only/tdd.spec.js diff --git a/test/mocha.spec.js b/test/mocha.spec.js deleted file mode 100644 index 618742cdbd..0000000000 --- a/test/mocha.spec.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -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.spec.js b/test/ms.spec.js deleted file mode 100644 index 26f5c30209..0000000000 --- a/test/ms.spec.js +++ /dev/null @@ -1,82 +0,0 @@ -'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/color.spec.js b/test/node-unit/color.spec.js similarity index 95% rename from test/color.spec.js rename to test/node-unit/color.spec.js index bffd30e6eb..ab27d2019e 100644 --- a/test/color.spec.js +++ b/test/node-unit/color.spec.js @@ -5,7 +5,7 @@ var childProcess = require('child_process'); var path = require('path'); describe('Mocha', function () { - this.timeout(2000); + this.timeout(4000); it('should not output colors to pipe', function (cb) { var command = [path.join('bin', 'mocha'), '--grep', 'missing-test']; diff --git a/test/acceptance/file-utils.spec.js b/test/node-unit/file-utils.spec.js similarity index 98% rename from test/acceptance/file-utils.spec.js rename to test/node-unit/file-utils.spec.js index 540589821d..3ff1bd4d7e 100644 --- a/test/acceptance/file-utils.spec.js +++ b/test/node-unit/file-utils.spec.js @@ -13,6 +13,10 @@ describe('file utils', function () { var tmpFile = path.join.bind(path, tmpDir); var symlinkSupported = false; + beforeEach(function () { + this.timeout(2000); + }); + (function testSymlinkSupport () { makeTempDir(); diff --git a/test/acceptance/fs.spec.js b/test/node-unit/fs.spec.js similarity index 100% rename from test/acceptance/fs.spec.js rename to test/node-unit/fs.spec.js diff --git a/test/http-meta-2.spec.js b/test/node-unit/http-meta-2.spec.js similarity index 97% rename from test/http-meta-2.spec.js rename to test/node-unit/http-meta-2.spec.js index 4530969041..18b4158467 100644 --- a/test/http-meta-2.spec.js +++ b/test/node-unit/http-meta-2.spec.js @@ -73,6 +73,10 @@ describe('http server', function () { server.listen(PORT, done); }); + beforeEach(function () { + this.timeout(2000); + }); + after(function () { server.close(); }); diff --git a/test/http-meta.spec.js b/test/node-unit/http-meta.spec.js similarity index 95% rename from test/http-meta.spec.js rename to test/node-unit/http-meta.spec.js index c92dbd2307..2ed7ed9204 100644 --- a/test/http-meta.spec.js +++ b/test/node-unit/http-meta.spec.js @@ -46,6 +46,10 @@ describe('http requests', function () { server.listen(PORT, done); }); + beforeEach(function () { + this.timeout(2000); + }); + after(function () { server.close(); }); diff --git a/test/acceptance/http.spec.js b/test/node-unit/http.spec.js similarity index 100% rename from test/acceptance/http.spec.js rename to test/node-unit/http.spec.js diff --git a/test/node-unit/stack-trace-filter.spec.js b/test/node-unit/stack-trace-filter.spec.js new file mode 100644 index 0000000000..72ce67a206 --- /dev/null +++ b/test/node-unit/stack-trace-filter.spec.js @@ -0,0 +1,156 @@ +'use strict'; + +var path = require('path'); +var utils = require('../../lib/utils'); + +describe('stackTraceFilter()', function () { + describe('on node', function () { + var filter = utils.stackTraceFilter(); + + describe('on POSIX OS', function () { + before(function () { + if (path.sep !== '/') { + this.skip(); + } + }); + + it('should get a stack-trace as a string and prettify it', function () { + var stack = [ + 'AssertionError: foo bar', + 'at EventEmitter. (/usr/local/dev/test.js:16:12)', + 'at Context. (/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. (/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, 7) + .join('\n')); + }); + + it('does not ignore other bower_components and components', function () { + var stack = [ + 'Error: failed', + 'at assert (index.html:11:26)', + 'at Context. (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')); + }); + + it('should replace absolute with relative paths', function () { + var stack = [ + 'Error: ' + process.cwd() + '/bla.js has a problem', + 'at foo (' + process.cwd() + '/foo/index.js:13:226)', + 'at bar (/usr/local/dev/own/tmp/node_modules/bluebird/js/main/promise.js:11:26)' + ]; + + var expected = [ + 'Error: ' + process.cwd() + '/bla.js has a problem', + 'at foo (foo/index.js:13:226)', + 'at bar (/usr/local/dev/own/tmp/node_modules/bluebird/js/main/promise.js:11:26)' + ]; + + filter(stack.join('\n')) + .should + .equal(expected.join('\n')); + }); + }); + + describe('on Windows', function () { + before(function () { + if (path.sep === '/') { + this.skip(); + } + }); + + it('should work on Windows', function () { + var stack = [ + 'Error: failed', + 'at Context. (C:\\Users\\ishida\\src\\test\\test\\mytest.js:5:9)', + 'at callFn (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runnable.js:326:21)', + 'at Test.Runnable.run (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runnable.js:319:7)', + 'at Runner.runTest (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:422:10)', + 'at C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:528:12', + 'at next (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:342:14)', + 'at C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:352:7', + 'at next (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:284:14)', + 'at Immediate._onImmediate (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:320:5)' + ]; + filter(stack.join('\n')) + .should + .equal(stack.slice(0, 2) + .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('does not strip out other bower_components', function () { + var stack = [ + 'Error: failed', + 'at assert (index.html:11:26)', + 'at Context. (test.js:17:18)', + 'at bower_components/should/should.js:4827:7', + 'at next (bower_components/should/should.js:4766:23)', + 'at components/should/5.0.0/should.js:4827:7', + 'at next (components/should/5.0.0/should.js:4766:23)', + 'at Runner.require.register.Runner.runTest (node_modules/mocha.js:4892:10)', + 'at localhost:3000/foo/bar/node_modules/mocha.js:4970:12', + 'at next (node_modules/mocha.js:4817:14)' + ]; + filter(stack.join('\n')) + .should + .equal(stack.slice(0, 7) + .join('\n')); + }); + + after(function () { + delete global.document; + delete global.location; + }); + }); +}); diff --git a/test/acceptance/require/a.js b/test/require/a.js similarity index 100% rename from test/acceptance/require/a.js rename to test/require/a.js diff --git a/test/acceptance/require/b.coffee b/test/require/b.coffee similarity index 100% rename from test/acceptance/require/b.coffee rename to test/require/b.coffee diff --git a/test/acceptance/require/c.js b/test/require/c.js similarity index 100% rename from test/acceptance/require/c.js rename to test/require/c.js diff --git a/test/acceptance/require/d.coffee b/test/require/d.coffee similarity index 100% rename from test/acceptance/require/d.coffee rename to test/require/d.coffee diff --git a/test/acceptance/require/require.spec.js b/test/require/require.spec.js similarity index 100% rename from test/acceptance/require/require.spec.js rename to test/require/require.spec.js diff --git a/test/acceptance/context.spec.js b/test/unit/context.spec.js similarity index 100% rename from test/acceptance/context.spec.js rename to test/unit/context.spec.js diff --git a/test/acceptance/duration.spec.js b/test/unit/duration.spec.js similarity index 100% rename from test/acceptance/duration.spec.js rename to test/unit/duration.spec.js diff --git a/test/acceptance/globals.spec.js b/test/unit/globals.spec.js similarity index 100% rename from test/acceptance/globals.spec.js rename to test/unit/globals.spec.js diff --git a/test/grep.spec.js b/test/unit/grep.spec.js similarity index 81% rename from test/grep.spec.js rename to test/unit/grep.spec.js index dd21cf0090..0e9b60ef7b 100644 --- a/test/grep.spec.js +++ b/test/unit/grep.spec.js @@ -1,24 +1,24 @@ 'use strict'; -var Mocha = require('../'); +var Mocha = require('../../lib/mocha'); 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.*/'); + expect(mocha.options.grep.toString()).to.equal('/foo.*/'); }); it('should convert string to a RegExp', function () { var mocha = new Mocha({ grep: 'foo.*' }); - mocha.options.grep.toString().should.equal('/foo.*/'); + expect(mocha.options.grep.toString()).to.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\\.\\*/'); + expect(mocha.options.grep.toString()).to.equal('/foo\\.\\*/'); }); }); @@ -27,7 +27,7 @@ describe('Mocha', function () { function testGrep (mocha) { return function testGrep (grep, expected) { mocha.grep(grep); - mocha.options.grep.toString().should.equal(expected); + expect(mocha.options.grep.toString()).to.equal(expected); }; } @@ -54,14 +54,14 @@ describe('Mocha', function () { it('should return it\'s parent Mocha object for chainability', function () { var mocha = new Mocha(); - mocha.grep().should.equal(mocha); + expect(mocha.grep()).to.equal(mocha); }); }); describe('"invert" option', function () { it('should add a Boolean to the mocha.options object', function () { var mocha = new Mocha({ invert: true }); - mocha.options.invert.should.be.ok; + expect(mocha.options.invert).to.be.ok; }); }); }); diff --git a/test/hook-async.spec.js b/test/unit/hook-async.spec.js similarity index 95% rename from test/hook-async.spec.js rename to test/unit/hook-async.spec.js index a03821e32c..523abd2d64 100644 --- a/test/hook-async.spec.js +++ b/test/unit/hook-async.spec.js @@ -9,7 +9,7 @@ describe('async', function () { after(function () { calls.push('root after all'); - calls.should.eql([ + expect(calls).to.eql([ 'root before all', 'before all', 'parent before', @@ -67,7 +67,7 @@ describe('async', function () { }); it('one', function (done) { - calls.should.eql([ + expect(calls).to.eql([ 'root before all', 'before all', 'parent before', @@ -79,7 +79,7 @@ describe('async', function () { }); it('two', function () { - calls.should.eql([ + expect(calls).to.eql([ 'root before all', 'before all', 'parent before', @@ -97,7 +97,7 @@ describe('async', function () { }); it('three', function () { - calls.should.eql([ + expect(calls).to.eql([ 'root before all', 'before all', 'parent before', diff --git a/test/hook-sync-nested.spec.js b/test/unit/hook-sync-nested.spec.js similarity index 95% rename from test/hook-sync-nested.spec.js rename to test/unit/hook-sync-nested.spec.js index 3f1929f547..25f9a7382f 100644 --- a/test/hook-sync-nested.spec.js +++ b/test/unit/hook-sync-nested.spec.js @@ -19,7 +19,7 @@ describe('serial', function () { }); it('foo', function () { - calls.should.eql([ + expect(calls).to.eql([ 'parent before', 'parent before test foo' ]); @@ -27,7 +27,7 @@ describe('serial', function () { }); it('bar', function () { - calls.should.eql([ + expect(calls).to.eql([ 'parent before', 'parent before test foo', 'foo', @@ -47,7 +47,7 @@ describe('serial', function () { }); it('one', function () { - calls.should.eql([ + expect(calls).to.eql([ 'parent before', 'parent before test foo', 'foo', @@ -66,7 +66,7 @@ describe('serial', function () { }); it('two', function () { - calls.should.eql([ + expect(calls).to.eql([ 'parent before', 'parent before test foo', 'foo', diff --git a/test/hook-sync.spec.js b/test/unit/hook-sync.spec.js similarity index 94% rename from test/hook-sync.spec.js rename to test/unit/hook-sync.spec.js index b1138a6db8..3f2b0508a8 100644 --- a/test/hook-sync.spec.js +++ b/test/unit/hook-sync.spec.js @@ -20,7 +20,7 @@ describe('serial', function () { }); it('one', function () { - calls.should.eql([ + expect(calls).to.eql([ 'parent before', 'before', 'before test one' @@ -29,7 +29,7 @@ describe('serial', function () { }); it('two', function () { - calls.should.eql([ + expect(calls).to.eql([ 'parent before', 'before', 'before test one', @@ -45,7 +45,7 @@ describe('serial', function () { }); it('three', function () { - calls.should.eql([ + expect(calls).to.eql([ 'parent before', 'before', 'before test one', @@ -75,7 +75,7 @@ describe('serial', function () { }); after(function () { - calls.should.eql([ + expect(calls).to.eql([ 'parent before', 'before', 'before test one', diff --git a/test/hook-timeout.spec.js b/test/unit/hook-timeout.spec.js similarity index 100% rename from test/hook-timeout.spec.js rename to test/unit/hook-timeout.spec.js diff --git a/test/unit/mocha.spec.js b/test/unit/mocha.spec.js new file mode 100644 index 0000000000..37b75ffd85 --- /dev/null +++ b/test/unit/mocha.spec.js @@ -0,0 +1,170 @@ +'use strict'; + +var Mocha = require('../../lib/mocha'); +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) { + expect(failures).to.equal(1); + done(); + }); + }); + }); + + describe('.addFile()', function () { + it('should add the given file to the files array', function () { + var mocha = new Mocha(blankOpts); + mocha.addFile('myFile.js'); + expect(mocha.files.length).to.equal(1); + expect(mocha.files[0]).to.equal('myFile.js'); + }); + }); + + describe('.invert()', function () { + it('should set the invert option to true', function () { + var mocha = new Mocha(blankOpts); + mocha.invert(); + expect(mocha.options.invert).to.equal(true); + }); + + it('should be chainable', function () { + var mocha = new Mocha(blankOpts); + expect(mocha.invert()).to.equal(mocha); + }); + }); + + describe('.ignoreLeaks()', function () { + it('should set the ignoreLeaks option to true when param equals true', function () { + var mocha = new Mocha(blankOpts); + mocha.ignoreLeaks(true); + expect(mocha.options.ignoreLeaks).to.equal(true); + }); + + it('should set the ignoreLeaks option to false when param equals false', function () { + var mocha = new Mocha(blankOpts); + mocha.ignoreLeaks(false); + expect(mocha.options.ignoreLeaks).to.equal(false); + }); + + it('should set the ignoreLeaks option to false when the param is undefined', function () { + var mocha = new Mocha(blankOpts); + mocha.ignoreLeaks(); + expect(mocha.options.ignoreLeaks).to.equal(false); + }); + + it('should be chainable', function () { + var mocha = new Mocha(blankOpts); + expect(mocha.ignoreLeaks(false)).to.equal(mocha); + }); + }); + + describe('.checkLeaks()', function () { + it('should set the ignoreLeaks option to false', function () { + var mocha = new Mocha(blankOpts); + mocha.checkLeaks(); + expect(mocha.options.ignoreLeaks).to.equal(false); + }); + + it('should be chainable', function () { + var mocha = new Mocha(blankOpts); + expect(mocha.checkLeaks()).to.equal(mocha); + }); + }); + + describe('.fullTrace()', function () { + it('should set the fullStackTrace option to true', function () { + var mocha = new Mocha(blankOpts); + mocha.fullTrace(); + expect(mocha.options.fullStackTrace).to.equal(true); + }); + + it('should be chainable', function () { + var mocha = new Mocha(blankOpts); + expect(mocha.fullTrace()).to.equal(mocha); + }); + }); + + describe('.growl()', function () { + it('should set the growl option to true', function () { + var mocha = new Mocha(blankOpts); + mocha.growl(); + expect(mocha.options.growl).to.equal(true); + }); + + it('should be chainable', function () { + var mocha = new Mocha(blankOpts); + expect(mocha.growl()).to.equal(mocha); + }); + }); + + describe('.useInlineDiffs()', function () { + it('should set the useInlineDiffs option to true when param equals true', function () { + var mocha = new Mocha(blankOpts); + mocha.useInlineDiffs(true); + expect(mocha.options.useInlineDiffs).to.equal(true); + }); + + it('should set the useInlineDiffs option to false when param equals false', function () { + var mocha = new Mocha(blankOpts); + mocha.useInlineDiffs(false); + expect(mocha.options.useInlineDiffs).to.equal(false); + }); + + it('should set the useInlineDiffs option to false when the param is undefined', function () { + var mocha = new Mocha(blankOpts); + mocha.useInlineDiffs(); + expect(mocha.options.useInlineDiffs).to.equal(false); + }); + + it('should be chainable', function () { + var mocha = new Mocha(blankOpts); + expect(mocha.useInlineDiffs()).to.equal(mocha); + }); + }); + + describe('.noHighlighting()', function () { + it('should set the noHighlighting option to true', function () { + var mocha = new Mocha(blankOpts); + mocha.noHighlighting(); + expect(mocha.options.noHighlighting).to.equal(true); + }); + }); + + describe('.allowUncaught()', function () { + it('should set the allowUncaught option to true', function () { + var mocha = new Mocha(blankOpts); + mocha.allowUncaught(); + expect(mocha.options.allowUncaught).to.equal(true); + }); + }); + + describe('.delay()', function () { + it('should set the delay option to true', function () { + var mocha = new Mocha(blankOpts); + mocha.delay(); + expect(mocha.options.delay).to.equal(true); + }); + }); +}); diff --git a/test/unit/ms.spec.js b/test/unit/ms.spec.js new file mode 100644 index 0000000000..189e126446 --- /dev/null +++ b/test/unit/ms.spec.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 () { + expect(ms(200)).to.equal('200ms'); + expect(ms(30)).to.equal('30ms'); + expect(ms(2000)).to.not.equal('2000ms'); + }); + }); + + describe('seconds representation', function () { + it('should return short format', function () { + expect(ms(2000)).to.equal('2s'); + }); + + it('should return long format', function () { + expect(ms(2000, { long: true })).to.equal('2 seconds'); + expect(ms(1000, { long: true })).to.equal('1 second'); + expect(ms(1010, { long: true })).to.equal('1 second'); + }); + }); + + describe('minutess representation', function () { + it('should return short format', function () { + expect(ms(time.minutes(1))).to.equal('1m'); + }); + + it('should return long format', function () { + expect(ms(time.minutes(1), { long: true })).to.equal('1 minute'); + expect(ms(time.minutes(3), { long: true })).to.equal('3 minutes'); + }); + }); + + describe('hours representation', function () { + it('should return short format', function () { + expect(ms(time.hours(1))).to.equal('1h'); + }); + + it('should return long format', function () { + expect(ms(time.hours(1), { long: true })).to.equal('1 hour'); + expect(ms(time.hours(3), { long: true })).to.equal('3 hours'); + }); + }); + + describe('days representation', function () { + it('should return short format', function () { + expect(ms(time.days(1))).to.equal('1d'); + }); + + it('should return long format', function () { + expect(ms(time.days(1), { long: true })).to.equal('1 day'); + expect(ms(time.days(3), { long: true })).to.equal('3 days'); + }); + }); + + describe('Getting string value', function () { + it('should return the milliseconds representation(Number)', function () { + expect(ms('1 second')).to.equal(1000); + + expect(ms('1 minute')).to.equal(time.minutes(1)); + expect(ms('6 minutes')).to.equal(time.minutes(6)); + + expect(ms('1 hour')).to.equal(time.hours(1)); + expect(ms('5 hours')).to.equal(time.hours(5)); + + expect(ms('1 day')).to.equal(time.days(1)); + expect(ms('3 days')).to.equal(time.days(3)); + + expect(ms('1 year')).to.equal(time.years(1)); + expect(ms('2 years')).to.equal(time.years(2)); + }); + }); +}); diff --git a/test/acceptance/overspecified-async.spec.js b/test/unit/overspecified-async.spec.js similarity index 100% rename from test/acceptance/overspecified-async.spec.js rename to test/unit/overspecified-async.spec.js diff --git a/test/acceptance/required-tokens.spec.js b/test/unit/required-tokens.spec.js similarity index 100% rename from test/acceptance/required-tokens.spec.js rename to test/unit/required-tokens.spec.js diff --git a/test/acceptance/root.spec.js b/test/unit/root.spec.js similarity index 100% rename from test/acceptance/root.spec.js rename to test/unit/root.spec.js diff --git a/test/runnable.spec.js b/test/unit/runnable.spec.js similarity index 81% rename from test/runnable.spec.js rename to test/unit/runnable.spec.js index 67cfcca38a..8c084281d2 100644 --- a/test/runnable.spec.js +++ b/test/unit/runnable.spec.js @@ -1,6 +1,6 @@ 'use strict'; -var mocha = require('../'); +var mocha = require('../../lib/mocha'); var utils = mocha.utils; var Runnable = mocha.Runnable; @@ -38,7 +38,7 @@ describe('Runnable(title, fn)', function () { it('should set the timeout', function () { var run = new Runnable(); run.timeout(1000); - run.timeout().should.equal(1000); + expect(run.timeout()).to.equal(1000); }); }); @@ -46,7 +46,7 @@ describe('Runnable(title, fn)', function () { it('should set disabled', function () { var run = new Runnable(); run.timeout(1e10); - run.enableTimeouts().should.be.false; + expect(run.enableTimeouts()).to.equal(false); }); }); @@ -54,7 +54,7 @@ describe('Runnable(title, fn)', function () { it('should set enabled', function () { var run = new Runnable(); run.enableTimeouts(false); - run.enableTimeouts().should.equal(false); + expect(run.enableTimeouts()).to.equal(false); }); }); @@ -67,47 +67,47 @@ describe('Runnable(title, fn)', function () { it('should set the slow threshold', function () { run.slow(100); - run.slow().should.equal(100); + expect(run.slow()).to.equal(100); }); it('should not set the slow threshold if the parameter is not passed', function () { run.slow(); - run.slow().should.equal(75); + expect(run.slow()).to.equal(75); }); it('should not set the slow threshold if the parameter is undefined', function () { run.slow(undefined); - run.slow().should.equal(75); + expect(run.slow()).to.equal(75); }); }); describe('.title', function () { it('should be present', function () { - new Runnable('foo').title.should.equal('foo'); + expect(new Runnable('foo').title).to.equal('foo'); }); }); describe('when arity >= 1', function () { it('should be .async', function () { var run = new Runnable('foo', function (done) {}); - run.async.should.equal(1); - run.sync.should.be.false(); + expect(run.async).to.equal(1); + expect(run.sync).to.be(false); }); }); describe('when arity == 0', function () { it('should be .sync', function () { var run = new Runnable('foo', function () {}); - run.async.should.be.equal(0); - run.sync.should.be.true(); + expect(run.async).to.be.equal(0); + expect(run.sync).to.be(true); }); }); describe('#globals', function () { it('should allow for whitelisting globals', function (done) { var test = new Runnable('foo', function () {}); - test.async.should.be.equal(0); - test.sync.should.be.true(); + expect(test.async).to.be.equal(0); + expect(test.sync).to.be(true); test.globals(['foobar']); test.run(done); }); @@ -117,7 +117,7 @@ describe('Runnable(title, fn)', function () { it('should set the number of retries', function () { var run = new Runnable(); run.retries(1); - run.retries().should.equal(1); + expect(run.retries()).to.equal(1); }); }); @@ -142,9 +142,24 @@ describe('Runnable(title, fn)', function () { }); test.run(function (err) { - calls.should.equal(1); - test.duration.should.be.type('number'); - done(err); + if (err) { + done(err); + return; + } + + try { + expect(calls) + .to + .equal(1); + expect(test.duration) + .to + .be + .a('number'); + } catch (err) { + done(err); + return; + } + done(); }); }); }); @@ -158,8 +173,8 @@ describe('Runnable(title, fn)', function () { }); test.run(function (err) { - calls.should.equal(1); - err.message.should.equal('fail'); + expect(calls).to.equal(1); + expect(err.message).to.equal('fail'); done(); }); }); @@ -174,7 +189,7 @@ describe('Runnable(title, fn)', function () { function fail () { test.run(function () {}); } - fail.should.throw('fail'); + expect(fail).to.throwError('fail'); done(); }); }); @@ -183,7 +198,9 @@ describe('Runnable(title, fn)', function () { describe('when timeouts are disabled', function () { it('should not error with timeout', function (done) { var test = new Runnable('foo', function (done) { - setTimeout(process.nextTick.bind(undefined, done), 2); + setTimeout(function () { + setTimeout(done); + }, 2); }); test.timeout(1); test.enableTimeouts(false); @@ -195,7 +212,7 @@ describe('Runnable(title, fn)', function () { describe('without error', function () { it('should invoke the callback', function (done) { var test = new Runnable('foo', function (done) { - process.nextTick(done); + setTimeout(done); }); test.run(done); @@ -210,16 +227,16 @@ describe('Runnable(title, fn)', function () { var test = new Runnable('foo', function (done) { process.nextTick(done); - process.nextTick(done); - process.nextTick(done); - process.nextTick(done); + setTimeout(done); + setTimeout(done); + setTimeout(done); }); test.on('error', function (err) { ++errCalls; - err.message.should.equal('done() called multiple times'); - calls.should.equal(1); - errCalls.should.equal(1); + expect(err.message).to.equal('done() called multiple times'); + expect(calls).to.equal(1); + expect(errCalls).to.equal(1); done(); }); @@ -236,17 +253,17 @@ describe('Runnable(title, fn)', function () { var test = new Runnable('foo', function (done) { done(new Error('fail')); - process.nextTick(done); + setTimeout(done); done(new Error('fail')); - process.nextTick(done); - process.nextTick(done); + setTimeout(done); + setTimeout(done); }); test.on('error', function (err) { ++errCalls; - err.message.should.equal('fail'); - calls.should.equal(1); - errCalls.should.equal(1); + expect(err.message).to.equal('fail'); + expect(calls).to.equal(1); + expect(errCalls).to.equal(1); done(); }); @@ -264,7 +281,7 @@ describe('Runnable(title, fn)', function () { }); test.run(function (err) { - err.message.should.equal('fail'); + expect(err.message).to.equal('fail'); done(); }); }); @@ -276,7 +293,7 @@ describe('Runnable(title, fn)', function () { }); test.run(function (err) { - err.message.should.equal(utils.undefinedError().message); + expect(err.message).to.equal(utils.undefinedError().message); done(); }); }); @@ -291,7 +308,7 @@ describe('Runnable(title, fn)', function () { function fail () { test.run(function () {}); } - fail.should.throw('fail'); + expect(fail).to.throwError('fail'); done(); }); }); @@ -303,7 +320,7 @@ describe('Runnable(title, fn)', function () { }); test.run(function (err) { - err.message.should.equal('fail'); + expect(err.message).to.equal('fail'); done(); }); }); @@ -316,7 +333,7 @@ describe('Runnable(title, fn)', function () { }); test.run(function (err) { - err.message.should.equal('done() invoked with non-Error: {"error":"Test error"}'); + expect(err.message).to.equal('done() invoked with non-Error: {"error":"Test error"}'); done(); }); }); @@ -329,7 +346,7 @@ describe('Runnable(title, fn)', function () { }); test.run(function (err) { - err.message.should.equal('done() invoked with non-Error: Test error'); + expect(err.message).to.equal('done() invoked with non-Error: Test error'); done(); }); }); @@ -344,10 +361,10 @@ describe('Runnable(title, fn)', function () { setTimeout(increment, 1); setTimeout(increment, 100); }); - test.timeout(10); + test.timeout(50); test.run(function (err) { - err.should.be.ok(); - callCount.should.equal(1); + expect(err).to.be.ok(); + expect(callCount).to.equal(1); done(); }); }); @@ -359,7 +376,7 @@ describe('Runnable(title, fn)', function () { describe('when the promise is fulfilled with no value', function () { var fulfilledPromise = { then: function (fulfilled, rejected) { - process.nextTick(fulfilled); + setTimeout(fulfilled); } }; @@ -375,7 +392,7 @@ describe('Runnable(title, fn)', function () { describe('when the promise is fulfilled with a value', function () { var fulfilledPromise = { then: function (fulfilled, rejected) { - process.nextTick(function () { + setTimeout(function () { fulfilled({}); }); } @@ -394,7 +411,7 @@ describe('Runnable(title, fn)', function () { var expectedErr = new Error('fail'); var rejectedPromise = { then: function (fulfilled, rejected) { - process.nextTick(function () { + setTimeout(function () { rejected(expectedErr); }); } @@ -406,7 +423,7 @@ describe('Runnable(title, fn)', function () { }); test.run(function (err) { - err.should.equal(expectedErr); + expect(err).to.equal(expectedErr); done(); }); }); @@ -416,7 +433,7 @@ describe('Runnable(title, fn)', function () { var expectedErr = new Error('Promise rejected with no or falsy reason'); var rejectedPromise = { then: function (fulfilled, rejected) { - process.nextTick(function () { + setTimeout(function () { rejected(); }); } @@ -428,7 +445,7 @@ describe('Runnable(title, fn)', function () { }); test.run(function (err) { - err.should.eql(expectedErr); + expect(err.message).to.equal(expectedErr.message); done(); }); }); @@ -446,7 +463,7 @@ describe('Runnable(title, fn)', function () { test.timeout(10); test.run(function (err) { - err.should.be.ok(); + expect(err).to.be.ok(); done(); }); }); diff --git a/test/runner.spec.js b/test/unit/runner.spec.js similarity index 81% rename from test/runner.spec.js rename to test/unit/runner.spec.js index 7c69846ec8..718a9b7cf6 100644 --- a/test/runner.spec.js +++ b/test/unit/runner.spec.js @@ -1,6 +1,6 @@ 'use strict'; -var mocha = require('../'); +var mocha = require('../../lib/mocha'); var Suite = mocha.Suite; var Runner = mocha.Runner; var Test = mocha.Test; @@ -24,7 +24,7 @@ describe('Runner', function () { suite.addTest(new Test('im a test about bears', noop)); var newRunner = new Runner(suite); newRunner.grep(/lions/); - newRunner.total.should.equal(2); + expect(newRunner.total).to.equal(2); }); it('should update the runner.total with number of matched tests when inverted', function () { @@ -33,7 +33,7 @@ describe('Runner', function () { suite.addTest(new Test('im a test about bears', noop)); var newRunner = new Runner(suite); newRunner.grep(/lions/, true); - newRunner.total.should.equal(1); + expect(newRunner.total).to.equal(1); }); }); @@ -43,7 +43,7 @@ describe('Runner', function () { suite.addTest(new Test('im another test about lions', noop)); suite.addTest(new Test('im a test about bears', noop)); runner.grep(/lions/); - runner.grepTotal(suite).should.equal(2); + expect(runner.grepTotal(suite)).to.equal(2); }); it('should return the total number of matched tests when inverted', function () { @@ -51,35 +51,41 @@ describe('Runner', function () { suite.addTest(new Test('im another test about lions', noop)); suite.addTest(new Test('im a test about bears', noop)); runner.grep(/lions/, true); - runner.grepTotal(suite).should.equal(1); + expect(runner.grepTotal(suite)).to.equal(1); }); }); describe('.globalProps()', function () { it('should include common non enumerable globals', function () { var props = runner.globalProps(); - props.should.containEql('setTimeout'); - props.should.containEql('clearTimeout'); - props.should.containEql('setInterval'); - props.should.containEql('clearInterval'); - props.should.containEql('Date'); - props.should.containEql('XMLHttpRequest'); + expect(props).to.contain('setTimeout'); + expect(props).to.contain('clearTimeout'); + expect(props).to.contain('setInterval'); + expect(props).to.contain('clearInterval'); + expect(props).to.contain('Date'); + expect(props).to.contain('XMLHttpRequest'); }); }); describe('.globals()', function () { it('should default to the known globals', function () { - runner.globals().length.should.be.above(16); + expect(runner.globals().length).to.be.above(16); }); it('should white-list globals', function () { runner.globals(['foo', 'bar']); - runner.globals().should.containEql('foo'); - runner.globals().should.containEql('bar'); + expect(runner.globals()).to.contain('foo'); + expect(runner.globals()).to.contain('bar'); }); }); describe('.checkGlobals(test)', function () { + before(function () { + if (!Object.create) { + this.skip(); + } + }); + it('should allow variables that match a wildcard', function (done) { runner.globals(['foo*', 'giz*']); global.foo = 'baz'; @@ -95,8 +101,8 @@ describe('Runner', function () { runner.checkGlobals(); global.foo = 'bar'; runner.on('fail', function (_test, err) { - _test.should.equal(test); - err.message.should.equal('global leak detected: foo'); + expect(_test).to.equal(test); + expect(err.message).to.equal('global leak detected: foo'); delete global.foo; done(); }); @@ -119,9 +125,12 @@ describe('Runner', function () { }); it('should not fail when a new common global is introduced', function () { + if (process.browser) { + this.skip(); + return; + } // verify that the prop isn't enumerable - delete global.XMLHttpRequest; - global.propertyIsEnumerable('XMLHttpRequest').should.not.be.ok(); + expect(global.propertyIsEnumerable('XMLHttpRequest')).to.not.be.ok(); // create a new runner and keep a reference to the test. var test = new Test('im a test about bears', noop); @@ -130,11 +139,11 @@ describe('Runner', function () { // make the prop enumerable again. global.XMLHttpRequest = function () {}; - global.propertyIsEnumerable('XMLHttpRequest').should.be.ok(); + expect(global.propertyIsEnumerable('XMLHttpRequest')).to.be.ok(); // verify the test hasn't failed. newRunner.checkGlobals(test); - test.should.not.have.key('state'); + expect(test).to.not.have.key('state'); // clean up our global space. delete global.XMLHttpRequest; @@ -146,8 +155,8 @@ describe('Runner', function () { global.foo = 'bar'; global.bar = 'baz'; runner.on('fail', function (_test, err) { - _test.should.equal(test); - err.message.should.equal('global leaks detected: foo, bar'); + expect(_test).to.equal(test); + expect(err.message).to.equal('global leaks detected: foo, bar'); delete global.foo; delete global.bar; done(); @@ -166,7 +175,7 @@ describe('Runner', function () { // verify the test hasn't failed. runner.checkGlobals(test); - test.should.not.have.key('state'); + expect(test).to.not.have.key('state'); delete global.foo; }); @@ -180,8 +189,8 @@ describe('Runner', function () { global.foo = 'bar'; global.bar = 'baz'; runner.on('fail', function (test, err) { - test.title.should.equal('im a test about lions'); - err.message.should.equal('global leak detected: bar'); + expect(test.title).to.equal('im a test about lions'); + expect(err.message).to.equal('global leak detected: bar'); delete global.foo; done(); }); @@ -214,25 +223,25 @@ describe('Runner', function () { describe('.fail(test, err)', function () { it('should increment .failures', function () { - runner.failures.should.equal(0); + expect(runner.failures).to.equal(0); runner.fail(new Test('one', noop), {}); - runner.failures.should.equal(1); + expect(runner.failures).to.equal(1); runner.fail(new Test('two', noop), {}); - runner.failures.should.equal(2); + expect(runner.failures).to.equal(2); }); it('should set test.state to "failed"', function () { var test = new Test('some test', noop); runner.fail(test, 'some error'); - test.state.should.equal('failed'); + expect(test.state).to.equal('failed'); }); it('should emit "fail"', function (done) { var test = new Test('some other test', noop); var err = {}; runner.on('fail', function (test, err) { - test.should.equal(test); - err.should.equal(err); + expect(test).to.equal(test); + expect(err).to.equal(err); done(); }); runner.fail(test, err); @@ -242,7 +251,7 @@ describe('Runner', function () { var test = new Test('helpful test', noop); var err = 'string'; runner.on('fail', function (test, err) { - err.message.should.equal('the string "string" was thrown, throw an Error :)'); + expect(err.message).to.equal('the string "string" was thrown, throw an Error :)'); done(); }); runner.fail(test, err); @@ -252,7 +261,7 @@ describe('Runner', function () { var test = new Test('a test', noop); var err = new Error('an error message'); runner.on('fail', function (test, err) { - err.message.should.equal('an error message'); + expect(err.message).to.equal('an error message'); done(); }); runner.fail(test, err); @@ -262,7 +271,7 @@ describe('Runner', function () { var test = new Test('a test', noop); var err = { message: 'an error message' }; runner.on('fail', function (test, err) { - err.message.should.equal('an error message'); + expect(err.message).to.equal('an error message'); done(); }); runner.fail(test, err); @@ -272,7 +281,7 @@ describe('Runner', function () { var test = new Test('a test', noop); var err = { x: 1 }; runner.on('fail', function (test, err) { - err.message.should.equal('the object {\n "x": 1\n} was thrown, throw an Error :)'); + expect(err.message).to.equal('the object {\n "x": 1\n} was thrown, throw an Error :)'); done(); }); runner.fail(test, err); @@ -285,13 +294,18 @@ describe('Runner', function () { 2 ]; runner.on('fail', function (test, err) { - err.message.should.equal('the array [\n 1\n 2\n] was thrown, throw an Error :)'); + expect(err.message).to.equal('the array [\n 1\n 2\n] was thrown, throw an Error :)'); done(); }); runner.fail(test, err); }); it('should recover if the error stack is not writable', function (done) { + if (!Object.create) { + this.skip(); + return; + } + var err = new Error('not evil'); Object.defineProperty(err, 'stack', { value: err.stack @@ -299,7 +313,7 @@ describe('Runner', function () { var test = new Test('a test', noop); runner.on('fail', function (test, err) { - err.message.should.equal('not evil'); + expect(err.message).to.equal('not evil'); done(); }); @@ -309,11 +323,11 @@ describe('Runner', function () { describe('.failHook(hook, err)', function () { it('should increment .failures', function () { - runner.failures.should.equal(0); + expect(runner.failures).to.equal(0); runner.failHook(new Test('fail hook 1', noop), {}); - runner.failures.should.equal(1); + expect(runner.failures).to.equal(1); runner.failHook(new Test('fail hook 2', noop), {}); - runner.failures.should.equal(2); + expect(runner.failures).to.equal(2); }); it('should augment hook title with current test title', function () { @@ -321,19 +335,19 @@ describe('Runner', function () { hook.ctx = { currentTest: new Test('should behave', noop) }; runner.failHook(hook, {}); - hook.title.should.equal('"before each" hook for "should behave"'); + expect(hook.title).to.equal('"before each" hook for "should behave"'); hook.ctx.currentTest = new Test('should obey', noop); runner.failHook(hook, {}); - hook.title.should.equal('"before each" hook for "should obey"'); + expect(hook.title).to.equal('"before each" hook for "should obey"'); }); it('should emit "fail"', function (done) { var hook = new Hook(); var err = {}; runner.on('fail', function (hook, err) { - hook.should.equal(hook); - err.should.equal(err); + expect(hook).to.equal(hook); + expect(err).to.equal(err); done(); }); runner.failHook(hook, err); @@ -369,7 +383,7 @@ describe('Runner', function () { function fail () { newRunner.runTest(); } - fail.should.throw('allow unhandled errors'); + expect(fail).to.throwError('allow unhandled errors'); done(); }); }); @@ -403,7 +417,7 @@ describe('Runner', function () { err.stack = stack.join('\n'); runner.on('fail', function (hook, err) { - err.stack.should.equal(stack.slice(0, 3).join('\n')); + expect(err.stack).to.equal(stack.slice(0, 3).join('\n')); done(); }); runner.failHook(hook, err); @@ -426,7 +440,7 @@ describe('Runner', function () { runner.fullStackTrace = true; runner.on('fail', function (hook, err) { - err.stack.should.equal(stack.join('\n')); + expect(err.stack).to.equal(stack.join('\n')); done(); }); runner.failHook(hook, err); diff --git a/test/suite.spec.js b/test/unit/suite.spec.js similarity index 63% rename from test/suite.spec.js rename to test/unit/suite.spec.js index 4cb62dd290..a4530e3c05 100644 --- a/test/suite.spec.js +++ b/test/unit/suite.spec.js @@ -1,9 +1,14 @@ 'use strict'; -var mocha = require('../'); +var mocha = require('../../lib/mocha'); var Suite = mocha.Suite; var Test = mocha.Test; +function supportsFunctionNames () { + // eslint-disable-next-line no-extra-parens + return (function foo () {}).name === 'foo'; +} + describe('Suite', function () { describe('.clone()', function () { beforeEach(function () { @@ -20,43 +25,43 @@ describe('Suite', function () { }); it('should copy the title', function () { - this.suite.clone().title.should.equal('To be cloned'); + expect(this.suite.clone().title).to.equal('To be cloned'); }); it('should copy the timeout value', function () { - this.suite.clone().timeout().should.equal(3043); + expect(this.suite.clone().timeout()).to.equal(3043); }); it('should copy the slow value', function () { - this.suite.clone().slow().should.equal(101); + expect(this.suite.clone().slow()).to.equal(101); }); it('should copy the bail value', function () { - this.suite.clone().bail().should.be.true(); + expect(this.suite.clone().bail()).to.be(true); }); it('should not copy the values from the suites array', function () { - this.suite.clone().suites.should.be.empty(); + expect(this.suite.clone().suites).to.be.empty(); }); it('should not copy the values from the tests array', function () { - this.suite.clone().tests.should.be.empty(); + expect(this.suite.clone().tests).to.be.empty(); }); it('should not copy the values from the _beforeEach array', function () { - this.suite.clone()._beforeEach.should.be.empty(); + expect(this.suite.clone()._beforeEach).to.be.empty(); }); it('should not copy the values from the _beforeAll array', function () { - this.suite.clone()._beforeAll.should.be.empty(); + expect(this.suite.clone()._beforeAll).to.be.empty(); }); it('should not copy the values from the _afterEach array', function () { - this.suite.clone()._afterEach.should.be.empty(); + expect(this.suite.clone()._afterEach).to.be.empty(); }); it('should not copy the values from the _afterAll array', function () { - this.suite.clone()._afterAll.should.be.empty(); + expect(this.suite.clone()._afterAll).to.be.empty(); }); }); @@ -67,14 +72,14 @@ describe('Suite', function () { describe('when no argument is passed', function () { it('should return the timeout value', function () { - this.suite.timeout().should.equal(2000); + expect(this.suite.timeout()).to.equal(2000); }); }); describe('when argument is passed', function () { it('should return the Suite object', function () { var newSuite = this.suite.timeout(5000); - newSuite.timeout().should.equal(5000); + expect(newSuite.timeout()).to.equal(5000); }); }); }); @@ -87,20 +92,20 @@ describe('Suite', function () { describe('when given a string', function () { it('should parse it', function () { this.suite.slow('5 seconds'); - this.suite.slow().should.equal(5000); + expect(this.suite.slow()).to.equal(5000); }); }); describe('when no argument is passed', function () { it('should return the slow value', function () { - this.suite.slow().should.equal(75); + expect(this.suite.slow()).to.equal(75); }); }); describe('when argument is passed', function () { it('should return the Suite object', function () { var newSuite = this.suite.slow(5000); - newSuite.slow().should.equal(5000); + expect(newSuite.slow()).to.equal(5000); }); }); }); @@ -113,14 +118,14 @@ describe('Suite', function () { describe('when no argument is passed', function () { it('should return the bail value', function () { - this.suite.bail().should.be.true(); + expect(this.suite.bail()).to.be(true); }); }); describe('when argument is passed', function () { it('should return the Suite object', function () { var newSuite = this.suite.bail(false); - newSuite.bail().should.be.false(); + expect(newSuite.bail()).to.be(false); }); }); }); @@ -135,27 +140,40 @@ describe('Suite', function () { var fn = function () {}; this.suite.beforeAll(fn); - this.suite._beforeAll.should.have.length(1); + expect(this.suite._beforeAll).to.have.length(1); var beforeAllItem = this.suite._beforeAll[0]; - beforeAllItem.title.should.match(/^"before all" hook/); - beforeAllItem.fn.should.equal(fn); + expect(beforeAllItem.title).to.match(/^"before all" hook/); + expect(beforeAllItem.fn).to.equal(fn); }); it('appends title to hook', function () { - var fn = function () {}; + var fn = function () { + }; this.suite.beforeAll('test', fn); - this.suite._beforeAll.should.have.length(1); + expect(this.suite._beforeAll) + .to + .have + .length(1); var beforeAllItem = this.suite._beforeAll[0]; - beforeAllItem.title.should.equal('"before all" hook: test'); - beforeAllItem.fn.should.equal(fn); + expect(beforeAllItem.title) + .to + .equal('"before all" hook: test'); + expect(beforeAllItem.fn) + .to + .equal(fn); + }); + it('uses function name if available', function () { + if (!supportsFunctionNames()) { + this.skip(); + return; + } function namedFn () {} this.suite.beforeAll(namedFn); - this.suite._beforeAll.should.have.length(2); - beforeAllItem = this.suite._beforeAll[1]; - beforeAllItem.title.should.equal('"before all" hook: namedFn'); - beforeAllItem.fn.should.equal(namedFn); + var beforeAllItem = this.suite._beforeAll[0]; + expect(beforeAllItem.title).to.equal('"before all" hook: namedFn'); + expect(beforeAllItem.fn).to.equal(namedFn); }); }); }); @@ -170,26 +188,39 @@ describe('Suite', function () { var fn = function () {}; this.suite.afterAll(fn); - this.suite._afterAll.should.have.length(1); + expect(this.suite._afterAll).to.have.length(1); var afterAllItem = this.suite._afterAll[0]; - afterAllItem.title.should.match(/^"after all" hook/); - afterAllItem.fn.should.equal(fn); + expect(afterAllItem.title).to.match(/^"after all" hook/); + expect(afterAllItem.fn).to.equal(fn); }); it('appends title to hook', function () { - var fn = function () {}; + var fn = function () { + }; this.suite.afterAll('test', fn); - this.suite._afterAll.should.have.length(1); + expect(this.suite._afterAll) + .to + .have + .length(1); var beforeAllItem = this.suite._afterAll[0]; - beforeAllItem.title.should.equal('"after all" hook: test'); - beforeAllItem.fn.should.equal(fn); + expect(beforeAllItem.title) + .to + .equal('"after all" hook: test'); + expect(beforeAllItem.fn) + .to + .equal(fn); + }); + it('uses function name if available', function () { + if (!supportsFunctionNames()) { + this.skip(); + return; + } function namedFn () {} this.suite.afterAll(namedFn); - this.suite._afterAll.should.have.length(2); - beforeAllItem = this.suite._afterAll[1]; - beforeAllItem.title.should.equal('"after all" hook: namedFn'); - beforeAllItem.fn.should.equal(namedFn); + var afterAllItem = this.suite._afterAll[0]; + expect(afterAllItem.title).to.equal('"after all" hook: namedFn'); + expect(afterAllItem.fn).to.equal(namedFn); }); }); }); @@ -204,27 +235,40 @@ describe('Suite', function () { var fn = function () {}; this.suite.beforeEach(fn); - this.suite._beforeEach.should.have.length(1); + expect(this.suite._beforeEach).to.have.length(1); var beforeEachItem = this.suite._beforeEach[0]; - beforeEachItem.title.should.match(/^"before each" hook/); - beforeEachItem.fn.should.equal(fn); + expect(beforeEachItem.title).to.match(/^"before each" hook/); + expect(beforeEachItem.fn).to.equal(fn); }); it('appends title to hook', function () { - var fn = function () {}; + var fn = function () { + }; this.suite.beforeEach('test', fn); - this.suite._beforeEach.should.have.length(1); + expect(this.suite._beforeEach) + .to + .have + .length(1); var beforeAllItem = this.suite._beforeEach[0]; - beforeAllItem.title.should.equal('"before each" hook: test'); - beforeAllItem.fn.should.equal(fn); + expect(beforeAllItem.title) + .to + .equal('"before each" hook: test'); + expect(beforeAllItem.fn) + .to + .equal(fn); + }); + it('uses function name if available', function () { + if (!supportsFunctionNames()) { + this.skip(); + return; + } function namedFn () {} this.suite.beforeEach(namedFn); - this.suite._beforeEach.should.have.length(2); - beforeAllItem = this.suite._beforeEach[1]; - beforeAllItem.title.should.equal('"before each" hook: namedFn'); - beforeAllItem.fn.should.equal(namedFn); + var beforeEachItem = this.suite._beforeEach[0]; + expect(beforeEachItem.title).to.equal('"before each" hook: namedFn'); + expect(beforeEachItem.fn).to.equal(namedFn); }); }); }); @@ -239,27 +283,40 @@ describe('Suite', function () { var fn = function () {}; this.suite.afterEach(fn); - this.suite._afterEach.should.have.length(1); + expect(this.suite._afterEach).to.have.length(1); var afterEachItem = this.suite._afterEach[0]; - afterEachItem.title.should.match(/^"after each" hook/); - afterEachItem.fn.should.equal(fn); + expect(afterEachItem.title).to.match(/^"after each" hook/); + expect(afterEachItem.fn).to.equal(fn); }); it('appends title to hook', function () { - var fn = function () {}; + var fn = function () { + }; this.suite.afterEach('test', fn); - this.suite._afterEach.should.have.length(1); + expect(this.suite._afterEach) + .to + .have + .length(1); var beforeAllItem = this.suite._afterEach[0]; - beforeAllItem.title.should.equal('"after each" hook: test'); - beforeAllItem.fn.should.equal(fn); + expect(beforeAllItem.title) + .to + .equal('"after each" hook: test'); + expect(beforeAllItem.fn) + .to + .equal(fn); + }); + it('uses function name if available', function () { + if (!supportsFunctionNames()) { + this.skip(); + return; + } function namedFn () {} this.suite.afterEach(namedFn); - this.suite._afterEach.should.have.length(2); - beforeAllItem = this.suite._afterEach[1]; - beforeAllItem.title.should.equal('"after each" hook: namedFn'); - beforeAllItem.fn.should.equal(namedFn); + var afterEachItem = this.suite._afterEach[0]; + expect(afterEachItem.title).to.equal('"after each" hook: namedFn'); + expect(afterEachItem.fn).to.equal(namedFn); }); }); }); @@ -274,25 +331,25 @@ describe('Suite', function () { }); it('sets the parent on the added Suite', function () { - this.second.parent.should.equal(this.first); + expect(this.second.parent).to.equal(this.first); }); it('copies the timeout value', function () { - this.second.timeout().should.equal(4002); + expect(this.second.timeout()).to.equal(4002); }); it('copies the slow value', function () { - this.second.slow().should.equal(200); + expect(this.second.slow()).to.equal(200); }); it('adds the suite to the suites collection', function () { - this.first.suites.should.have.length(1); - this.first.suites[0].should.equal(this.second); + expect(this.first.suites).to.have.length(1); + expect(this.first.suites[0]).to.equal(this.second); }); it('treats suite as pending if its parent is pending', function () { this.first.pending = true; - this.second.isPending.should.be.true; + expect(this.second.isPending()).to.be(true); }); }); @@ -325,7 +382,7 @@ describe('Suite', function () { describe('when there is no parent', function () { it('returns the suite title', function () { - this.suite.fullTitle().should.equal('A Suite'); + expect(this.suite.fullTitle()).to.equal('A Suite'); }); }); @@ -333,7 +390,7 @@ describe('Suite', function () { it('returns the combination of parent\'s and suite\'s title', function () { var parentSuite = new Suite('I am a parent'); parentSuite.addSuite(this.suite); - this.suite.fullTitle().should.equal('I am a parent A Suite'); + expect(this.suite.fullTitle()).to.equal('I am a parent A Suite'); }); }); }); @@ -345,7 +402,7 @@ describe('Suite', function () { describe('when there are no nested suites or tests', function () { it('should return 0', function () { - this.suite.total().should.equal(0); + expect(this.suite.total()).to.equal(0); }); }); @@ -353,7 +410,7 @@ describe('Suite', function () { it('should return the number', function () { this.suite.addTest(new Test('a child test')); this.suite.addTest(new Test('another child test')); - this.suite.total().should.equal(2); + expect(this.suite.total()).to.equal(2); }); }); }); @@ -368,7 +425,7 @@ describe('Suite', function () { var n = 0; function fn () { n++; } this.suite.eachTest(fn); - n.should.equal(0); + expect(n).to.equal(0); }); }); @@ -380,7 +437,7 @@ describe('Suite', function () { var n = 0; function fn () { n++; } this.suite.eachTest(fn); - n.should.equal(2); + expect(n).to.equal(2); }); }); @@ -394,7 +451,7 @@ describe('Suite', function () { var n = 0; function fn () { n++; } this.suite.eachTest(fn); - n.should.equal(2); + expect(n).to.equal(2); }); }); }); @@ -402,19 +459,19 @@ describe('Suite', function () { describe('initialization', function () { /* eslint no-new: off */ it('should throw an error if the title isn\'t a string', function () { - (function () { + expect(function () { new Suite(undefined, 'root'); - }).should.throw(); + }).to.throwError(); - (function () { + expect(function () { new Suite(function () {}, 'root'); - }).should.throw(); + }).to.throwError(); }); it('should not throw if the title is a string', function () { - (function () { + expect(function () { new Suite('Bdd suite', 'root'); - }).should.not.throw(); + }).to.not.throwError(); }); }); }); @@ -422,19 +479,19 @@ describe('Suite', function () { describe('Test', function () { describe('initialization', function () { it('should throw an error if the title isn\'t a string', function () { - (function () { + expect(function () { new Test(function () {}); - }).should.throw(); + }).to.throwError(); - (function () { + expect(function () { new Test(undefined, function () {}); - }).should.throw(); + }).to.throwError(); }); it('should not throw if the title is a string', function () { - (function () { + expect(function () { new Test('test-case', function () {}); - }).should.not.throw(); + }).to.not.throwError(); }); }); }); diff --git a/test/test.spec.js b/test/unit/test.spec.js similarity index 67% rename from test/test.spec.js rename to test/unit/test.spec.js index 73c09b3b06..86aa5effa3 100644 --- a/test/test.spec.js +++ b/test/unit/test.spec.js @@ -1,7 +1,6 @@ 'use strict'; -var mocha = require('../'); -var should = require('should'); +var mocha = require('../../lib/mocha'); var Test = mocha.Test; describe('Test', function () { @@ -19,39 +18,39 @@ describe('Test', function () { }); it('should copy the title', function () { - this._test.clone().title.should.equal('To be cloned'); + expect(this._test.clone().title).to.equal('To be cloned'); }); it('should copy the timeout value', function () { - this._test.clone().timeout().should.equal(3043); + expect(this._test.clone().timeout()).to.equal(3043); }); it('should copy the slow value', function () { - this._test.clone().slow().should.equal(101); + expect(this._test.clone().slow()).to.equal(101); }); it('should copy the enableTimeouts value', function () { - this._test.clone().enableTimeouts().should.be.true(); + expect(this._test.clone().enableTimeouts()).to.be(true); }); it('should copy the retries value', function () { - this._test.clone().retries().should.equal(3); + expect(this._test.clone().retries()).to.equal(3); }); it('should copy the currentRetry value', function () { - this._test.clone().currentRetry().should.equal(1); + expect(this._test.clone().currentRetry()).to.equal(1); }); it('should copy the globals value', function () { - this._test.clone().globals().should.not.be.empty(); + expect(this._test.clone().globals()).to.not.be.empty(); }); it('should copy the parent value', function () { - this._test.clone().parent.should.equal('foo'); + expect(this._test.clone().parent).to.equal('foo'); }); it('should copy the file value', function () { - this._test.clone().file.should.equal('bar'); + expect(this._test.clone().file).to.equal('bar'); }); }); @@ -61,17 +60,17 @@ describe('Test', function () { }); it('should not be pending by default', function () { - should(this._test.isPending()).not.be.ok(); + expect(this._test.isPending()).to.not.be(true); }); it('should be pending when marked as such', function () { this._test.pending = true; - should(this._test.isPending()).be.ok(); + expect(this._test.isPending()).to.be(true); }); it('should be pending when its parent is pending', function () { this._test.parent = { isPending: function () { return true; } }; - should(this._test.isPending()).be.ok(); + expect(this._test.isPending()).to.be(true); }); }); }); diff --git a/test/acceptance/throw.spec.js b/test/unit/throw.spec.js similarity index 100% rename from test/acceptance/throw.spec.js rename to test/unit/throw.spec.js diff --git a/test/acceptance/timeout.spec.js b/test/unit/timeout.spec.js similarity index 100% rename from test/acceptance/timeout.spec.js rename to test/unit/timeout.spec.js diff --git a/test/acceptance/utils.spec.js b/test/unit/utils.spec.js similarity index 70% rename from test/acceptance/utils.spec.js rename to test/unit/utils.spec.js index 545bdfd265..ad64fd847c 100644 --- a/test/acceptance/utils.spec.js +++ b/test/unit/utils.spec.js @@ -6,13 +6,80 @@ var JSON = require('json3'); describe('lib/utils', function () { describe('clean', function () { + it('should remove the wrapping function declaration', function () { + expect(utils.clean('function (one, two, three) {\n//code\n}')) + .to + .equal('//code'); + }); + + it('should handle newlines in the function declaration', function () { + expect(utils.clean('function (one, two, three)\n {\n//code\n}')) + .to + .equal('//code'); + }); + + it('should remove space character indentation from the function body', + function () { + expect(utils.clean(' //line1\n //line2')) + .to + .equal('//line1\n //line2'); + }); + + it('should remove tab character indentation from the function body', + function () { + expect(utils.clean('\t//line1\n\t\t//line2')) + .to + .equal('//line1\n\t//line2'); + }); + + it('should handle functions with tabs in their declarations', function () { + expect(utils.clean('function\t(\t)\t{\n//code\n}')) + .to + .equal('//code'); + }); + + it('should handle named functions without space after name', function () { + expect(utils.clean('function withName() {\n//code\n}')) + .to + .equal('//code'); + }); + + it('should handle named functions with space after name', function () { + expect(utils.clean('function withName () {\n//code\n}')) + .to + .equal('//code'); + }); + + it( + 'should handle functions with no space between the end and the closing brace', + function () { + expect(utils.clean('function() {/*code*/}')) + .to + .equal('/*code*/'); + }); + + it('should handle functions with parentheses in the same line', + function () { + expect(utils.clean('function() { if (true) { /* code */ } }')) + .to + .equal('if (true) { /* code */ }'); + }); + + it('should handle empty functions', function () { + expect(utils.clean('function() {}')) + .to + .equal(''); + }); + it('should format a single line test function', function () { var fn = [ 'function () {', ' var a = 1;', '}' ].join('\n'); - expect(utils.clean(fn)).to.equal('var a = 1;'); + expect(utils.clean(fn)) + .to + .equal('var a = 1;'); }); it('should format a multi line test indented with spaces', function () { @@ -23,7 +90,9 @@ describe('lib/utils', function () { ' var b = 2;', ' var c = 3; }' ].join('\n'); - expect(utils.clean(fn)).to.equal('var a = 1;\n var b = 2;\nvar c = 3;'); + expect(utils.clean(fn)) + .to + .equal('var a = 1;\n var b = 2;\nvar c = 3;'); }); it('should format a multi line test indented with tabs', function () { @@ -34,7 +103,9 @@ describe('lib/utils', function () { '\t}', '}' ].join('\n'); - expect(utils.clean(fn)).to.equal('if (true) {\n\tvar a = 1;\n}'); + expect(utils.clean(fn)) + .to + .equal('if (true) {\n\tvar a = 1;\n}'); }); it('should format functions saved in windows style - spaces', function () { @@ -45,7 +116,9 @@ describe('lib/utils', function () { ' } while (false);', ' }' ].join('\r\n'); - expect(utils.clean(fn)).to.equal('do {\n "nothing";\n} while (false);'); + expect(utils.clean(fn)) + .to + .equal('do {\n "nothing";\n} while (false);'); }); it('should format functions saved in windows style - tabs', function () { @@ -58,7 +131,9 @@ describe('lib/utils', function () { '\t}', '}' ].join('\r\n'); - expect(utils.clean(fn)).to.equal('if (false) {\n\tvar json = {\n\t\tone : 1\n\t};\n}'); + expect(utils.clean(fn)) + .to + .equal('if (false) {\n\tvar json = {\n\t\tone : 1\n\t};\n}'); }); it('should format es6 arrow functions', function () { @@ -67,12 +142,16 @@ describe('lib/utils', function () { ' var a = 1;', '}' ].join('\n'); - expect(utils.clean(fn)).to.equal('var a = 1;'); + expect(utils.clean(fn)) + .to + .equal('var a = 1;'); }); it('should format es6 arrow functions with implicit return', function () { var fn = '() => foo()'; - expect(utils.clean(fn)).to.equal('foo()'); + expect(utils.clean(fn)) + .to + .equal('foo()'); }); }); @@ -415,4 +494,134 @@ describe('lib/utils', function () { Object.prototype.toString = toString; }); }); + + describe('isBuffer()', function () { + var isBuffer = utils.isBuffer; + it('should test if object is a Buffer', function () { + expect(isBuffer(new Buffer([0x01]))) + .to + .equal(true); + expect(isBuffer({})) + .to + .equal(false); + }); + }); + + describe('map()', function () { + var map = utils.map; + it('should behave same as Array.prototype.map', function () { + if (!Array.prototype.map) { + this.skip(); + return; + } + + var arr = [ + 1, + 2, + 3 + ]; + expect(map(arr, JSON.stringify)) + .to + .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) { + expect(e).to.equal(arr[index]); + expect(i).to.equal(index++); + }); + }); + + it('should apply with the given scope', function () { + var scope = {}; + map([ + 'a', + 'b', + 'c' + ], function () { + expect(this).to.equal(scope); + }, scope); + }); + }); + + describe('some()', function () { + var some = utils.some; + + it( + 'should return true when some array elements pass the check of the fn parameter', + function () { + var result = some([ + 'a', + 'b', + 'c' + ], function (e) { + return e === 'b'; + }); + expect(result).to.eql(true); + }); + + it( + 'should return false when none of the array elements pass the check of the fn parameter', + function () { + var result = some([ + 'a', + 'b', + 'c' + ], function (e) { + return e === 'd'; + }); + expect(result).to.eql(false); + }); + }); + + describe('parseQuery()', function () { + var parseQuery = utils.parseQuery; + it('should get queryString and return key-value object', function () { + expect(parseQuery('?foo=1&bar=2&baz=3')) + .to + .eql({ + foo: '1', + bar: '2', + baz: '3' + }); + + expect(parseQuery('?r1=^@(?!.*\\)$)&r2=m{2}&r3=^co.*')) + .to + .eql({ + r1: '^@(?!.*\\)$)', + r2: 'm{2}', + r3: '^co.*' + }); + }); + + it('should parse "+" as a space', function () { + expect(parseQuery('?grep=foo+bar')) + .to + .eql({grep: 'foo bar'}); + }); + }); + + describe('isPromise', function () { + it('should return true if the value is Promise-ish', function () { + expect(utils.isPromise({ + then: function () { + } + })).to.be(true); + }); + + it('should return false if the value is not an object', function () { + expect(utils.isPromise(1)).to.be(false); + }); + + it('should return false if the value is an object w/o a "then" function', + function () { + expect(utils.isPromise({})).to.be(false); + }); + }); }); diff --git a/test/utils.spec.js b/test/utils.spec.js deleted file mode 100644 index 2eaf908cd6..0000000000 --- a/test/utils.spec.js +++ /dev/null @@ -1,285 +0,0 @@ -'use strict'; - -var mocha = require('..'); -var utils = mocha.utils; -var path = require('path'); -var JSON = require('json3'); - -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 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 () { - clean('\t//line1\n\t\t//line2').should.equal('//line1\n\t//line2'); - }); - - it('should handle functions with tabs in their declarations', function () { - clean('function\t(\t)\t{\n//code\n}').should.equal('//code'); - }); - - it('should handle named functions without space after name', function () { - clean('function withName() {\n//code\n}').should.equal('//code'); - }); - - it('should handle named functions with space after name', function () { - clean('function withName () {\n//code\n}').should.equal('//code'); - }); - - it('should handle functions with no space between the end and the closing brace', function () { - clean('function() {/*code*/}').should.equal('/*code*/'); - }); - - it('should handle functions with parentheses in the same line', function () { - clean('function() { if (true) { /* code */ } }').should.equal('if (true) { /* code */ }'); - }); - - it('should handle empty functions', function () { - clean('function() {}').should.equal(''); - }); - }); - - 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('.some()', function () { - var some = utils.some; - - it('should return true when some array elements pass the check of the fn parameter', function () { - var result = some(['a', 'b', 'c'], function (e) { - return e === 'b'; - }); - result.should.eql(true); - }); - - it('should return false when none of the array elements pass the check of the fn parameter', function () { - var result = some(['a', 'b', 'c'], function (e) { - return e === 'd'; - }); - result.should.eql(false); - }); - }); - - 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.*' - }); - }); - - it('should parse "+" as a space', function () { - parseQuery('?grep=foo+bar').should.eql({grep: 'foo bar'}); - }); - }); - - describe('.stackTraceFilter()', function () { - describe('on node', function () { - var filter = utils.stackTraceFilter(); - - describe('on POSIX OS', function () { - before(function () { - if (path.sep !== '/') { - this.skip(); - } - }); - - it('should get a stack-trace as a string and prettify it', function () { - var stack = [ - 'AssertionError: foo bar', - 'at EventEmitter. (/usr/local/dev/test.js:16:12)', - 'at Context. (/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. (/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, 7) - .join('\n')); - }); - - it('does not ignore other bower_components and components', - function () { - var stack = [ - 'Error: failed', - 'at assert (index.html:11:26)', - 'at Context. (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')); - }); - - it('should replace absolute with relative paths', function () { - var stack = [ - 'Error: ' + process.cwd() + '/bla.js has a problem', - 'at foo (' + process.cwd() + '/foo/index.js:13:226)', - 'at bar (/usr/local/dev/own/tmp/node_modules/bluebird/js/main/promise.js:11:26)' - ]; - - var expected = [ - 'Error: ' + process.cwd() + '/bla.js has a problem', - 'at foo (foo/index.js:13:226)', - 'at bar (/usr/local/dev/own/tmp/node_modules/bluebird/js/main/promise.js:11:26)' - ]; - - filter(stack.join('\n')) - .should - .equal(expected.join('\n')); - }); - }); - - describe('on Windows', function () { - before(function () { - if (path.sep === '/') { - this.skip(); - } - }); - - it('should work on Windows', function () { - var stack = [ - 'Error: failed', - 'at Context. (C:\\Users\\ishida\\src\\test\\test\\mytest.js:5:9)', - 'at callFn (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runnable.js:326:21)', - 'at Test.Runnable.run (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runnable.js:319:7)', - 'at Runner.runTest (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:422:10)', - 'at C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:528:12', - 'at next (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:342:14)', - 'at C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:352:7', - 'at next (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:284:14)', - 'at Immediate._onImmediate (C:\\Users\\ishida\\src\\test\\node_modules\\mocha\\lib\\runner.js:320:5)' - ]; - filter(stack.join('\n')) - .should - .equal(stack.slice(0, 2) - .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('does not strip out other bower_components', function () { - var stack = [ - 'Error: failed', - 'at assert (index.html:11:26)', - 'at Context. (test.js:17:18)', - 'at bower_components/should/should.js:4827:7', - 'at next (bower_components/should/should.js:4766:23)', - 'at components/should/5.0.0/should.js:4827:7', - 'at next (components/should/5.0.0/should.js:4766:23)', - 'at Runner.require.register.Runner.runTest (node_modules/mocha.js:4892:10)', - 'at localhost:3000/foo/bar/node_modules/mocha.js:4970:12', - 'at next (node_modules/mocha.js:4817:14)' - ]; - filter(stack.join('\n')).should.equal(stack.slice(0, 7).join('\n')); - }); - - after(function () { - delete global.document; - delete global.location; - }); - }); - }); - - describe('.isPromise', function () { - it('should return true if the value is Promise-ish', function () { - utils.isPromise({then: function () {}}).should.be.true; - }); - - it('should return false if the value is not an object', function () { - utils.isPromise(1).should.be.false; - }); - - it('should return false if the value is an object w/o a "then" function', function () { - utils.isPromise({}).should.be.false; - }); - }); -});