diff --git a/README.md b/README.md index 502ee0f..8819678 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,27 @@ return assert.isRejected(promise, Error, "optional message"); return assert.isRejected(promise, /error message matcher/, "optional message"); ``` +### Asserting on a Promise Rejected with a Non-Error Object + +Like Chai's `throw` assertion, `rejectedWith` can only be used to assert on the constructor and message of `Error` instances. This includes `Error` instances created from subclassed `Error` constructors such as `ReferenceError`, `TypeError`, and user-defined constructors that extend `Error`. No other type of value will generate a stack trace when initialized. With that said, it's still possible to assert on non-`Error` objects by using `rejected` and then performing additional assertions later in the chain, like so: + +```js +it("should work when a promise is rejected with a non-`Error` object", function () { + function NonErrorConstructor(message) { + this.message = message; + } + + return expect(Promise.reject(new NonErrorConstructor("waffles"))) + .to.be.rejected + .and.eventually.be.an.instanceof(NonErrorConstructor) + .with.property("message", "waffles"); +}); + +it("should work when a promise is rejected with a primitive value", function () { + return expect(Promise.reject(42)).to.be.rejected.and.eventually.equal(42); +}); +``` + ### Progress Callbacks Chai as Promised does not have any intrinsic support for testing promise progress callbacks. The properties you would want to test are probably much better suited to a library like [Sinon.JS](http://sinonjs.org/), perhaps in conjunction with [Sinon–Chai](https://github.com/domenic/sinon-chai): diff --git a/lib/chai-as-promised.js b/lib/chai-as-promised.js index 0b84194..0c6e5bf 100644 --- a/lib/chai-as-promised.js +++ b/lib/chai-as-promised.js @@ -1,19 +1,12 @@ "use strict"; /* eslint-disable no-invalid-this */ -let checkError = require("check-error"); +const checkError = require("check-error"); module.exports = (chai, utils) => { const Assertion = chai.Assertion; const assert = chai.assert; const proxify = utils.proxify; - // If we are using a version of Chai that has checkError on it, - // we want to use that version to be consistent. Otherwise, we use - // what was passed to the factory. - if (utils.checkError) { - checkError = utils.checkError; - } - function isLegacyJQueryPromise(thenable) { // jQuery promises are Promises/A+-compatible since 3.0.0. jQuery 3.0.0 is also the first version // to define the catch method. @@ -76,10 +69,6 @@ module.exports = (chai, utils) => { return typeof assertion.then === "function" ? assertion : assertion._obj; } - function getReasonName(reason) { - return reason instanceof Error ? reason.toString() : checkError.getConstructorName(reason); - } - // Grab these first, before we modify `Assertion.prototype`. const propertyNames = Object.getOwnPropertyNames(Assertion.prototype); @@ -100,7 +89,7 @@ module.exports = (chai, utils) => { reason => { assertIfNotNegated(this, "expected promise to be fulfilled but it was rejected with #{act}", - { actual: getReasonName(reason) }); + { actual: reason }); return reason; } ); @@ -120,7 +109,7 @@ module.exports = (chai, utils) => { reason => { assertIfNegated(this, "expected promise not to be rejected but it was rejected with #{act}", - { actual: getReasonName(reason) }); + { actual: reason }); // Return the reason, transforming this into a fulfillment, to allow further assertions, e.g. // `promise.should.be.rejected.and.eventually.equal("reason")`. @@ -132,95 +121,52 @@ module.exports = (chai, utils) => { return this; }); - method("rejectedWith", function (errorLike, errMsgMatcher, message) { - let errorLikeName = null; - const negate = utils.flag(this, "negate") || false; + method("rejectedWith", function (errLike, errMsgMatcher, message) { + if (message !== undefined) { + utils.flag(this, "message", message); + } - // rejectedWith with that is called without arguments is + // rejectedWith that is called without arguments is // the same as a plain ".rejected" use. - if (errorLike === undefined && errMsgMatcher === undefined && + if (errLike === undefined && errMsgMatcher === undefined && message === undefined) { /* eslint-disable no-unused-expressions */ return this.rejected; /* eslint-enable no-unused-expressions */ } - if (message !== undefined) { - utils.flag(this, "message", message); - } - - if (errorLike instanceof RegExp || typeof errorLike === "string") { - errMsgMatcher = errorLike; - errorLike = null; - } else if (errorLike && errorLike instanceof Error) { - errorLikeName = errorLike.toString(); - } else if (typeof errorLike === "function") { - errorLikeName = checkError.getConstructorName(errorLike); - } else { - errorLike = null; - } - const everyArgIsDefined = Boolean(errorLike && errMsgMatcher); + const criteria = checkError.createCriteria(errLike, errMsgMatcher); + const expectedDesc = checkError.describeExpectedError(criteria); - let matcherRelation = "including"; - if (errMsgMatcher instanceof RegExp) { - matcherRelation = "matching"; - } + // We append the expected value instead of using #{exp} because #{exp} + // adds single quotes around the expected value, even when it doesn't + // make sense (e.g., "expected promise to be rejected with 'a TypeError'"). + const failMsg = "expected promise to be rejected with " + expectedDesc; + let negatedFailMsg = "expected promised not to be rejected with " + expectedDesc; const derivedPromise = getBasePromise(this).then( value => { - let assertionMessage = null; - let expected = null; - - if (errorLike) { - assertionMessage = "expected promise to be rejected with #{exp} but it was fulfilled with #{act}"; - expected = errorLikeName; - } else if (errMsgMatcher) { - assertionMessage = `expected promise to be rejected with an error ${matcherRelation} #{exp} but ` + - `it was fulfilled with #{act}`; - expected = errMsgMatcher; - } - - assertIfNotNegated(this, assertionMessage, { expected, actual: value }); + this.assert( + false, + failMsg + " but it was fulfilled with #{act}", + negatedFailMsg, + errLike || errMsgMatcher, + value + ); return value; }, reason => { - const errorLikeCompatible = errorLike && (errorLike instanceof Error ? - checkError.compatibleInstance(reason, errorLike) : - checkError.compatibleConstructor(reason, errorLike)); - - const errMsgMatcherCompatible = errMsgMatcher && checkError.compatibleMessage(reason, errMsgMatcher); - - const reasonName = getReasonName(reason); - - if (negate && everyArgIsDefined) { - if (errorLikeCompatible && errMsgMatcherCompatible) { - this.assert(true, - null, - "expected promise not to be rejected with #{exp} but it was rejected " + - "with #{act}", - errorLikeName, - reasonName); - } - } else { - if (errorLike) { - this.assert(errorLikeCompatible, - "expected promise to be rejected with #{exp} but it was rejected with #{act}", - "expected promise not to be rejected with #{exp} but it was rejected " + - "with #{act}", - errorLikeName, - reasonName); - } - - if (errMsgMatcher) { - this.assert(errMsgMatcherCompatible, - `expected promise to be rejected with an error ${matcherRelation} #{exp} but got ` + - `#{act}`, - `expected promise not to be rejected with an error ${matcherRelation} #{exp}`, - errMsgMatcher, - checkError.getMessage(reason)); - } - } - + if (reason !== errLike) { + negatedFailMsg += " but it was rejected with #{act}"; + } // Else, it's implicit and doesn't need to be added. + + this.assert( + checkError.checkError(reason, criteria), + failMsg + " but it was rejected with #{act}", + negatedFailMsg, + errLike || errMsgMatcher, + reason + ); return reason; } ); diff --git a/package-lock.json b/package-lock.json index d114e53..a8b7172 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,6 +2,7 @@ "name": "chai-as-promised", "version": "7.1.1", "lockfileVersion": 1, + "requires": true, "dependencies": { "abbrev": { "version": "1.0.9", @@ -20,6 +21,9 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, + "requires": { + "acorn": "3.3.0" + }, "dependencies": { "acorn": { "version": "3.3.0", @@ -33,7 +37,11 @@ "version": "4.11.8", "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } }, "ajv-keywords": { "version": "1.5.1", @@ -45,7 +53,12 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } }, "amdefine": { "version": "1.0.1", @@ -75,13 +88,19 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", - "dev": true + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } }, "array-uniq": { "version": "1.0.3", @@ -95,12 +114,6 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, - "assertion-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", - "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", - "dev": true - }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -111,7 +124,12 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } }, "balanced-match": { "version": "1.0.0", @@ -123,7 +141,11 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } }, "browser-stdout": { "version": "1.3.0", @@ -135,7 +157,10 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true + "dev": true, + "requires": { + "callsites": "0.2.0" + } }, "callsites": { "version": "0.2.0", @@ -155,24 +180,56 @@ "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, - "optional": true + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } }, "chai": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.0.2.tgz", - "integrity": "sha1-L3MnxN5vOF3XeHmZ4qsCaXoyuDs=", - "dev": true + "version": "git+https://github.com/meeber/chai.git#aa886d28cc2bf6912b97775ad6ccae6b3c75a111", + "dev": true, + "requires": { + "assertion-error": "1.1.0", + "check-error": "git+https://github.com/meeber/check-error.git#c72b57376e5778f8797783f59e6bddaa6f456b67", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.5" + }, + "dependencies": { + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + } + } }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } }, "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + "version": "git+https://github.com/meeber/check-error.git#c72b57376e5778f8797783f59e6bddaa6f456b67", + "requires": { + "get-func-name": "1.0.0" + } }, "circular-json": { "version": "0.3.1", @@ -184,7 +241,10 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } }, "cli-width": { "version": "2.1.0", @@ -198,6 +258,11 @@ "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, "dependencies": { "wordwrap": { "version": "0.0.2", @@ -224,7 +289,10 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } }, "concat-map": { "version": "0.0.1", @@ -236,7 +304,12 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "dev": true + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } }, "core-util-is": { "version": "1.0.2", @@ -248,13 +321,19 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", - "dev": true + "dev": true, + "requires": { + "es5-ext": "0.10.23" + } }, "debug": { "version": "2.6.8", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true + "dev": true, + "requires": { + "ms": "2.0.0" + } }, "decamelize": { "version": "1.2.0", @@ -264,17 +343,12 @@ "optional": true }, "deep-eql": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-2.0.2.tgz", - "integrity": "sha1-sbrAblbwp2d3aG1Qyf63XC7XZ5o=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, - "dependencies": { - "type-detect": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-3.0.0.tgz", - "integrity": "sha1-RtDMhVOrt7E6NSsNbeov1Y8tm1U=", - "dev": true - } + "requires": { + "type-detect": "4.0.5" } }, "deep-is": { @@ -287,7 +361,16 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.1" + } }, "diff": { "version": "3.2.0", @@ -299,43 +382,81 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", - "dev": true + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } }, "es5-ext": { "version": "0.10.23", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.23.tgz", "integrity": "sha1-dXi1G+l0IHpUh4IbVlOMIk5Oezg=", - "dev": true + "dev": true, + "requires": { + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } }, "es6-iterator": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23", + "es6-symbol": "3.1.1" + } }, "es6-map": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23", + "es6-iterator": "2.0.1", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } }, "es6-symbol": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23" + } }, "es6-weak-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } }, "escape-string-regexp": { "version": "1.0.5", @@ -348,6 +469,13 @@ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, + "requires": { + "esprima": "2.7.3", + "estraverse": "1.9.3", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.2.0" + }, "dependencies": { "esprima": { "version": "2.7.3", @@ -367,19 +495,66 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "dev": true + "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } }, "eslint": { "version": "3.19.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", - "dev": true + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "chalk": "1.1.3", + "concat-stream": "1.6.0", + "debug": "2.6.8", + "doctrine": "2.0.0", + "escope": "3.6.0", + "espree": "3.4.3", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "glob": "7.1.2", + "globals": "9.18.0", + "ignore": "3.3.3", + "imurmurhash": "0.1.4", + "inquirer": "0.12.0", + "is-my-json-valid": "2.16.0", + "is-resolvable": "1.0.0", + "js-yaml": "3.8.4", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "1.2.1", + "progress": "1.1.8", + "require-uncached": "1.0.3", + "shelljs": "0.7.8", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1", + "table": "3.8.3", + "text-table": "0.2.0", + "user-home": "2.0.0" + } }, "espree": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", - "dev": true + "dev": true, + "requires": { + "acorn": "5.0.3", + "acorn-jsx": "3.0.1" + } }, "esprima": { "version": "3.1.3", @@ -391,13 +566,20 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", - "dev": true + "dev": true, + "requires": { + "estraverse": "4.2.0" + } }, "esrecurse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", - "dev": true + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + } }, "estraverse": { "version": "4.2.0", @@ -415,7 +597,11 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23" + } }, "exit-hook": { "version": "1.1.1", @@ -433,19 +619,33 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } }, "file-entry-cache": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true + "dev": true, + "requires": { + "flat-cache": "1.2.2", + "object-assign": "4.1.1" + } }, "flat-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", - "dev": true + "dev": true, + "requires": { + "circular-json": "0.3.1", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } }, "fs.realpath": { "version": "1.0.0", @@ -463,19 +663,29 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true + "dev": true, + "requires": { + "is-property": "1.0.2" + } }, "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-1.0.0.tgz", + "integrity": "sha1-1k442o5FrLdGcmBJ82vviev6kcI=" }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } }, "globals": { "version": "9.18.0", @@ -487,7 +697,15 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } }, "graceful-fs": { "version": "4.1.11", @@ -512,12 +730,21 @@ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, "dependencies": { "source-map": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true + "dev": true, + "requires": { + "amdefine": "1.0.1" + } } } }, @@ -525,7 +752,10 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } }, "has-flag": { "version": "1.0.0", @@ -549,7 +779,11 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } }, "inherits": { "version": "2.0.3", @@ -561,7 +795,22 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dev": true + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "ansi-regex": "2.1.1", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.1.0", + "figures": "1.7.0", + "lodash": "4.17.4", + "readline2": "1.0.1", + "run-async": "0.1.0", + "rx-lite": "3.1.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } }, "interpret": { "version": "1.0.3", @@ -579,13 +828,22 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } }, "is-my-json-valid": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", - "dev": true + "dev": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } }, "is-path-cwd": { "version": "1.0.0", @@ -597,13 +855,19 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", - "dev": true + "dev": true, + "requires": { + "is-path-inside": "1.0.0" + } }, "is-path-inside": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", - "dev": true + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } }, "is-property": { "version": "1.0.2", @@ -615,7 +879,10 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", - "dev": true + "dev": true, + "requires": { + "tryit": "1.0.3" + } }, "isarray": { "version": "1.0.0", @@ -634,6 +901,22 @@ "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, + "requires": { + "abbrev": "1.0.9", + "async": "1.5.2", + "escodegen": "1.8.1", + "esprima": "2.7.3", + "glob": "5.0.15", + "handlebars": "4.0.10", + "js-yaml": "3.8.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "once": "1.4.0", + "resolve": "1.1.7", + "supports-color": "3.2.3", + "which": "1.2.14", + "wordwrap": "1.0.0" + }, "dependencies": { "esprima": { "version": "2.7.3", @@ -645,7 +928,14 @@ "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } }, "resolve": { "version": "1.1.7", @@ -657,7 +947,10 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true + "dev": true, + "requires": { + "has-flag": "1.0.0" + } } } }, @@ -671,13 +964,20 @@ "version": "3.8.4", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz", "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=", - "dev": true + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "3.1.3" + } }, "json-stable-stringify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true + "dev": true, + "requires": { + "jsonify": "0.0.0" + } }, "json3": { "version": "3.3.2", @@ -701,7 +1001,10 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } }, "lazy-cache": { "version": "1.0.4", @@ -714,7 +1017,11 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } }, "lodash": { "version": "4.17.4", @@ -726,7 +1033,11 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", - "dev": true + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } }, "lodash._basecopy": { "version": "3.0.1", @@ -756,7 +1067,12 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", - "dev": true + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } }, "lodash.isarguments": { "version": "3.1.0", @@ -774,7 +1090,12 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } }, "longest": { "version": "1.0.1", @@ -786,7 +1107,10 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } }, "minimist": { "version": "0.0.8", @@ -798,25 +1122,52 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true + "dev": true, + "requires": { + "minimist": "0.0.8" + } }, "mocha": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.4.2.tgz", "integrity": "sha1-0O9NMyEm2/GNDWQMmzgt1IvpdZQ=", "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.0", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, "dependencies": { "debug": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", - "dev": true + "dev": true, + "requires": { + "ms": "0.7.2" + } }, "glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", - "dev": true + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } }, "ms": { "version": "0.7.2", @@ -828,7 +1179,10 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", - "dev": true + "dev": true, + "requires": { + "has-flag": "1.0.0" + } } } }, @@ -854,7 +1208,10 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true + "dev": true, + "requires": { + "abbrev": "1.0.9" + } }, "number-is-nan": { "version": "1.0.1", @@ -872,7 +1229,10 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true + "dev": true, + "requires": { + "wrappy": "1.0.2" + } }, "onetime": { "version": "1.1.0", @@ -885,6 +1245,10 @@ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + }, "dependencies": { "wordwrap": { "version": "0.0.3", @@ -898,7 +1262,15 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } }, "os-homedir": { "version": "1.0.2", @@ -946,7 +1318,10 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true + "dev": true, + "requires": { + "pinkie": "2.0.4" + } }, "pluralize": { "version": "1.2.1", @@ -976,19 +1351,36 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } }, "readline2": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dev": true + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "mute-stream": "0.0.5" + } }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true + "dev": true, + "requires": { + "resolve": "1.3.3" + } }, "repeat-string": { "version": "1.6.1", @@ -1000,13 +1392,20 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } }, "resolve": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", - "dev": true + "dev": true, + "requires": { + "path-parse": "1.0.5" + } }, "resolve-from": { "version": "1.0.1", @@ -1018,26 +1417,39 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, - "optional": true + "optional": true, + "requires": { + "align-text": "0.1.4" + } }, "rimraf": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", - "dev": true + "dev": true, + "requires": { + "glob": "7.1.2" + } }, "run-async": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", - "dev": true + "dev": true, + "requires": { + "once": "1.4.0" + } }, "rx-lite": { "version": "3.1.2", @@ -1055,7 +1467,12 @@ "version": "0.7.8", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", - "dev": true + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.0.3", + "rechoir": "0.6.2" + } }, "slice-ansi": { "version": "0.0.4", @@ -1068,7 +1485,10 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, - "optional": true + "optional": true, + "requires": { + "amdefine": "1.0.1" + } }, "sprintf-js": { "version": "1.0.3", @@ -1076,23 +1496,34 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } }, "strip-bom": { "version": "3.0.0", @@ -1117,6 +1548,14 @@ "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.4", + "slice-ansi": "0.0.4", + "string-width": "2.1.0" + }, "dependencies": { "ansi-regex": { "version": "3.0.0", @@ -1134,13 +1573,20 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz", "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=", - "dev": true + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } } } }, @@ -1166,12 +1612,15 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } }, "type-detect": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", - "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.5.tgz", + "integrity": "sha512-N9IvkQslUGYGC24RkJk1ba99foK6TkwC2FHAEBlQFBP0RxQZS8ZpJuAZcwiY/w9ZJHFQb1aOXBI60OdxhTrwEQ==", "dev": true }, "typedarray": { @@ -1186,6 +1635,11 @@ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, + "requires": { + "source-map": "0.5.6", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, "dependencies": { "source-map": { "version": "0.5.6", @@ -1207,7 +1661,10 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", - "dev": true + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } }, "util-deprecate": { "version": "1.0.2", @@ -1219,7 +1676,10 @@ "version": "1.2.14", "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true + "dev": true, + "requires": { + "isexe": "2.0.0" + } }, "window-size": { "version": "0.1.0", @@ -1244,7 +1704,10 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } }, "xtend": { "version": "4.0.1", @@ -1257,7 +1720,13 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, - "optional": true + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } } } } diff --git a/package.json b/package.json index 3c4cda9..340f41f 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,13 @@ "cover": "istanbul cover node_modules/mocha/bin/_mocha && opener ./coverage/lcov-report/lib/chai-as-promised.js.html" }, "dependencies": { - "check-error": "^1.0.2" + "check-error": "git+https://github.com/meeber/check-error.git#add-check-error-function" }, "peerDependencies": { "chai": ">= 2.1.2 < 5" }, "devDependencies": { - "chai": "^4.0.2", + "chai": "git+https://github.com/meeber/chai.git#add-error-assertion", "eslint": "^3.19.0", "istanbul": "0.4.5", "mocha": "^3.4.2" diff --git a/test/assert-promise-specific.js b/test/assert-promise-specific.js index af6d641..dd6dbf8 100644 --- a/test/assert-promise-specific.js +++ b/test/assert-promise-specific.js @@ -82,14 +82,6 @@ describe("Assert interface:", () => { message: "to be rejected" }); }); - // Chai never interprets the 3rd parameter to assert.throws as - // a custom error message. This is what we are checking here. - describe(".isRejected(promise, /quux/, custom)", () => { - shouldFail({ - op: () => assert.isRejected(promise, /quux/, custom), - notMessage: custom - }); - }); }); @@ -127,15 +119,6 @@ describe("Assert interface:", () => { }); }); - // Chai never interprets the 3rd parameter to assert.throws as - // a custom error message. This is what we are checking here. - describe(".isRejected(promise, differentError, custom)", () => { - shouldFail({ - op: () => assert.isRejected(promise, new Error(), custom), - notMessage: custom - }); - }); - describe("with an Error having message 'foo bar'", () => { beforeEach(() => { promise = Promise.reject(new Error("foo bar")); @@ -145,18 +128,10 @@ describe("Assert interface:", () => { shouldPass(() => assert.isRejected(promise, "bar")); }); - describe(".isRejected(promise, 'bar', custom)", () => { - shouldPass(() => assert.isRejected(promise, "bar", custom)); - }); - describe(".isRejected(promise, /bar/)", () => { shouldPass(() => assert.isRejected(promise, /bar/)); }); - describe(".isRejected(promise, /bar/, custom)", () => { - shouldPass(() => assert.isRejected(promise, /bar/, custom)); - }); - describe(".isRejected(promise, 'quux')", () => { shouldFail({ op: () => assert.isRejected(promise, "quux"), @@ -164,15 +139,6 @@ describe("Assert interface:", () => { }); }); - // Chai 3.5.0 never interprets the 3rd parameter to assert.throws as - // a custom error message. This is what we are checking here. - describe(".isRejected(promise, 'quux', custom)", () => { - shouldFail({ - op: () => assert.isRejected(promise, "quux", custom), - notMessage: custom - }); - }); - describe(".isRejected(promise, /quux/)", () => { shouldFail({ op: () => assert.isRejected(promise, /quux/), @@ -214,40 +180,46 @@ describe("Assert interface:", () => { describe(".isRejected(promise, RangeError, 'quux')", () => { shouldFail({ op: () => assert.isRejected(promise, RangeError, "quux"), - message: "to be rejected with an error including 'quux' but got 'foo bar'" + message: "to be rejected with a RangeError including 'quux' but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".isRejected(promise, RangeError, /quux/)", () => { shouldFail({ op: () => assert.isRejected(promise, RangeError, /quux/), - message: "to be rejected with an error matching /quux/ but got 'foo bar'" + message: "to be rejected with a RangeError matching /quux/ but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".isRejected(promise, TypeError, 'foo')", () => { shouldFail({ op: () => assert.isRejected(promise, TypeError, "foo"), - message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" + message: "to be rejected with a TypeError including 'foo' but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".isRejected(promise, TypeError, /bar/)", () => { shouldFail({ op: () => assert.isRejected(promise, TypeError, /bar/), - message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" + message: "to be rejected with a TypeError matching /bar/ but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".isRejected(promise, TypeError, 'quux')", () => { shouldFail({ op: () => assert.isRejected(promise, TypeError, "quux"), - message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" + message: "to be rejected with a TypeError including 'quux' but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".isRejected(promise, TypeError, /quux/)", () => { shouldFail({ op: () => assert.isRejected(promise, TypeError, /quux/), - message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" + message: "to be rejected with a TypeError matching /quux/ but it was rejected with" + + " [RangeError: foo bar]" }); }); @@ -285,4 +257,38 @@ describe("Assert interface:", () => { }); }); }); + + describe("when invalid arguments are given to isRejected", () => { + beforeEach(() => { + promise = Promise.reject(error); + }); + + it("2nd arg is a string and 3rd arg is defined", () => { + assert.throws( + () => assert.isRejected(promise, "testing", "testing"), + "errMsgMatcher must be null or undefined when errLike is a string or regular expression" + ); + }); + + it("2nd arg isn't an `Error` constructor, `Error` instance, string, or regexp", () => { + assert.throws( + () => assert.isRejected(promise, {}), + "errLike must be an Error constructor or instance" + ); + }); + + it("3rd arg is defined but not a string or regexp", () => { + assert.throws( + () => assert.isRejected(promise, TypeError, {}), + "errMsgMatcher must be a string or regular expression" + ); + }); + + it("2nd arg is an `Error` instance and 3rd arg is defined", () => { + assert.throws( + () => assert.isRejected(promise, error, "testing"), + "errMsgMatcher must be null or undefined when errLike is an Error instance" + ); + }); + }); }); diff --git a/test/proxy-guard.js b/test/proxy-guard.js index bf7397e..bc3198a 100644 --- a/test/proxy-guard.js +++ b/test/proxy-guard.js @@ -62,7 +62,7 @@ describe("Proxy guard", () => { }); it("should guard against invalid property following called `.rejectedWith`", () => { - shouldGuard(() => promise.should.rejectedWith(42).pizza, "pizza"); + shouldGuard(() => promise.should.rejectedWith("42").pizza, "pizza"); }); it("should guard against invalid property following uncalled `.rejectedWith`", () => { diff --git a/test/should-promise-specific.js b/test/should-promise-specific.js index 2653100..e692e86 100644 --- a/test/should-promise-specific.js +++ b/test/should-promise-specific.js @@ -70,7 +70,7 @@ describe("Promise-specific extensions:", () => { describe(".rejectedWith(TypeError)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(TypeError), - message: "to be rejected with 'TypeError' but it was fulfilled with 42" + message: "to be rejected with a TypeError but it was fulfilled with 42" }); }); describe(".not.rejectedWith(TypeError) passes the fulfilled value", () => { @@ -86,32 +86,32 @@ describe("Promise-specific extensions:", () => { describe(".rejectedWith('message substring')", () => { shouldFail({ op: () => promise.should.be.rejectedWith("message substring"), - message: "to be rejected with an error including 'message substring' but it was fulfilled with " + + message: "to be rejected with an Error including 'message substring' but it was fulfilled with " + "42" }); }); describe(".rejectedWith(/regexp/)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(/regexp/), - message: "to be rejected with an error matching /regexp/ but it was fulfilled with 42" + message: "to be rejected with an Error matching /regexp/ but it was fulfilled with 42" }); }); describe(".rejectedWith(TypeError, 'message substring')", () => { shouldFail({ op: () => promise.should.be.rejectedWith(TypeError, "message substring"), - message: "to be rejected with 'TypeError' but it was fulfilled with 42" + message: "to be rejected with a TypeError including 'message substring' but it was fulfilled with 42" }); }); describe(".rejectedWith(TypeError, /regexp/)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(TypeError, /regexp/), - message: "to be rejected with 'TypeError' but it was fulfilled with 42" + message: "to be rejected with a TypeError matching /regexp/ but it was fulfilled with 42" }); }); describe(".rejectedWith(errorInstance)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(error), - message: "to be rejected with 'Error: boo' but it was fulfilled with 42" + message: "to be rejected with [Error: boo] but it was fulfilled with 42" }); }); @@ -152,7 +152,7 @@ describe("Promise-specific extensions:", () => { describe(".fulfilled", () => { shouldFail({ op: () => promise.should.be.fulfilled, - message: "to be fulfilled but it was rejected with 'Error: boo'" + message: "to be fulfilled but it was rejected with [Error: boo]" }); }); @@ -177,7 +177,7 @@ describe("Promise-specific extensions:", () => { describe(".not.rejected", () => { shouldFail({ op: () => promise.should.not.be.rejected, - message: "not to be rejected but it was rejected with 'Error: boo'" + message: "not to be rejected but it was rejected with [Error: boo]" }); }); describe(".rejected should allow chaining", () => { @@ -197,7 +197,7 @@ describe("Promise-specific extensions:", () => { describe(".not.rejectedWith(theError)", () => { shouldFail({ op: () => promise.should.not.be.rejectedWith(error), - message: "not to be rejected with 'Error: boo'" + message: "not to be rejected with [Error: boo]" }); }); @@ -214,7 +214,7 @@ describe("Promise-specific extensions:", () => { describe(".rejectedWith(differentError)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(new Error()), - message: "to be rejected with 'Error' but it was rejected with 'Error: boo'" + message: "to be rejected with [Error] but it was rejected with [Error: boo]" }); }); @@ -222,21 +222,6 @@ describe("Promise-specific extensions:", () => { shouldPass(() => promise.should.not.be.rejectedWith(new Error())); }); - // Chai 3.5.0 never interprets the 2nd paramter to - // expect(fn).to.throw(a, b) as a custom error message. This is - // what we are testing here. - describe(".rejectedWith(differentError, custom)", () => { - shouldFail({ - op: () => promise.should.be.rejectedWith(new Error(), custom), - message: "to be rejected with 'Error' but it was rejected with 'Error: boo'", - notMessage: custom - }); - }); - - describe(".not.rejectedWith(differentError, custom)", () => { - shouldPass(() => promise.should.not.be.rejectedWith(new Error(), custom)); - }); - describe("with an Error having message 'foo bar'", () => { beforeEach(() => { promise = Promise.reject(new Error("foo bar")); @@ -249,7 +234,7 @@ describe("Promise-specific extensions:", () => { describe(".not.rejectedWith('foo')", () => { shouldFail({ op: () => promise.should.not.be.rejectedWith("foo"), - message: "not to be rejected with an error including 'foo'" + message: "not to be rejected with an Error including 'foo'" }); }); @@ -260,14 +245,14 @@ describe("Promise-specific extensions:", () => { describe(".not.rejectedWith(/bar/)", () => { shouldFail({ op: () => promise.should.not.be.rejectedWith(/bar/), - message: "not to be rejected with an error matching /bar/" + message: "not to be rejected with an Error matching /bar/" }); }); describe(".rejectedWith('quux')", () => { shouldFail({ op: () => promise.should.be.rejectedWith("quux"), - message: "to be rejected with an error including 'quux' but got 'foo bar'" + message: "to be rejected with an Error including 'quux' but it was rejected with [Error: foo bar]" }); }); @@ -278,7 +263,7 @@ describe("Promise-specific extensions:", () => { describe(".rejectedWith(/quux/)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(/quux/), - message: "to be rejected with an error matching /quux/ but got 'foo bar'" + message: "to be rejected with an Error matching /quux/ but it was rejected with [Error: foo bar]" }); }); @@ -286,29 +271,11 @@ describe("Promise-specific extensions:", () => { shouldPass(() => promise.should.not.be.rejectedWith(/quux/)); }); - // Chai 3.5.0 never interprets the 2nd paramter to - // expect(fn).to.throw(a, b) as a custom error - // message. This is what we are testing here. - describe(".rejectedWith('foo', custom)", () => { - shouldPass(() => promise.should.be.rejectedWith("foo", custom)); - }); - - describe(".not.rejectedWith('foo', custom)", () => { - shouldFail({ - op: () => promise.should.not.be.rejectedWith("foo", custom), - message: "not to be rejected with an error including 'foo'", - notMessage: custom - }); - }); - - describe(".rejectedWith(/bar/, custom)", () => { - shouldPass(() => promise.should.be.rejectedWith(/bar/, custom)); - }); - describe(".not.rejectedWith(/bar/, custom)", () => { shouldFail({ op: () => promise.should.not.be.rejectedWith(/bar/), - message: "not to be rejected with an error matching /bar/", + message: "not to be rejected with an Error matching /bar/ but it was rejected with" + + " [Error: foo bar]", notMessage: custom }); }); @@ -326,22 +293,14 @@ describe("Promise-specific extensions:", () => { describe(".not.rejectedWith(RangeError)", () => { shouldFail({ op: () => promise.should.not.be.rejectedWith(RangeError), - message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError'" + message: "not to be rejected with a RangeError but it was rejected with [RangeError]" }); }); describe(".rejectedWith(TypeError)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(TypeError), - message: "to be rejected with 'TypeError' but it was rejected with 'RangeError'" - }); - }); - - // Case for issue #64. - describe(".rejectedWith(Array)", () => { - shouldFail({ - op: () => promise.should.be.rejectedWith(Array), - message: "to be rejected with 'Array' but it was rejected with 'RangeError'" + message: "to be rejected with a TypeError but it was rejected with [RangeError]" }); }); @@ -362,7 +321,8 @@ describe("Promise-specific extensions:", () => { describe(".not.rejectedWith(RangeError, 'foo')", () => { shouldFail({ op: () => promise.should.not.be.rejectedWith(RangeError, "foo"), - message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError: foo bar'" + message: "not to be rejected with a RangeError including 'foo' but it was rejected with" + + " [RangeError: foo bar]" }); }); @@ -373,59 +333,68 @@ describe("Promise-specific extensions:", () => { describe(".not.rejectedWith(RangeError, /bar/)", () => { shouldFail({ op: () => promise.should.not.be.rejectedWith(RangeError, /bar/), - message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError: foo bar'" + message: "not to be rejected with a RangeError matching /bar/ but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".rejectedWith(RangeError, 'quux')", () => { shouldFail({ op: () => promise.should.be.rejectedWith(RangeError, "quux"), - message: "to be rejected with an error including 'quux' but got 'foo bar'" + message: "to be rejected with a RangeError including 'quux' but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".rejectedWith(RangeError, /quux/)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(RangeError, /quux/), - message: "to be rejected with an error matching /quux/ but got 'foo bar'" + message: "to be rejected with a RangeError matching /quux/ but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".rejectedWith(TypeError, 'foo')", () => { shouldFail({ op: () => promise.should.be.rejectedWith(TypeError, "foo"), - message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" + message: "to be rejected with a TypeError including 'foo' but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".rejectedWith(TypeError, /bar/)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(TypeError, /bar/), - message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" + message: "to be rejected with a TypeError matching /bar/ but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".rejectedWith(TypeError, 'quux')", () => { shouldFail({ op: () => promise.should.be.rejectedWith(TypeError, "quux"), - message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" + message: "to be rejected with a TypeError including 'quux' but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".rejectedWith(TypeError, /quux/)", () => { shouldFail({ op: () => promise.should.be.rejectedWith(TypeError, /quux/), - message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" + message: "to be rejected with a TypeError matching /quux/ but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".not.rejectedWith(RangeError, 'foo')", () => { shouldFail({ op: () => promise.should.not.be.rejectedWith(RangeError, "foo"), - message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError: foo bar'" + message: "not to be rejected with a RangeError including 'foo' but it was rejected with" + + " [RangeError: foo bar]" }); }); describe(".not.rejectedWith(RangeError, /bar/)", () => { shouldFail({ op: () => promise.should.not.be.rejectedWith(RangeError, /bar/), - message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError: foo bar'" + message: "not to be rejected with a RangeError matching /bar/ but it was rejected with" + + " [RangeError: foo bar]" }); }); @@ -633,7 +602,29 @@ describe("Promise-specific extensions:", () => { }); }); - describe("`rejectedWith` with non-`Error` rejection reasons (GH-33)", () => { - shouldPass(() => Promise.reject(42).should.be.rejectedWith(42)); + describe("when invalid arguments are given to rejectedWith", () => { + beforeEach(() => { + promise = Promise.reject(error); + }); + + it("1st arg is a string and 2nd arg is defined", () => { + expect(() => promise.should.be.rejectedWith("testing", "testing")) + .to.throw("errMsgMatcher must be null or undefined when errLike is a string or regular expression"); + }); + + it("1st arg isn't an `Error` constructor, `Error` instance, string, or regexp", () => { + expect(() => promise.should.be.rejectedWith({})) + .to.throw("errLike must be an Error constructor or instance"); + }); + + it("2nd arg is defined but not a string or regexp", () => { + expect(() => promise.should.be.rejectedWith(TypeError, {})) + .to.throw("errMsgMatcher must be a string or regular expression"); + }); + + it("1st arg is an `Error` instance and 2nd arg is defined", () => { + expect(() => promise.should.be.rejectedWith(error, "testing")) + .to.throw("errMsgMatcher must be null or undefined when errLike is an Error instance"); + }); }); });