diff --git a/.gitignore b/.gitignore index efccf60..fc74dac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/package-lock.json node_modules/ npm-debug.log /tmp diff --git a/.travis.yml b/.travis.yml index fa4ac7b..1c39b29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,11 @@ language: node_js node_js: - '4' - '6' + - '8' deploy: provider: script script: ./node_modules/.bin/nlm release skip_cleanup: true 'on': branch: master - node: '6' + node: '8' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c94d4df..4633dce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ If you report a bug, please follow these guidelines: For small documentation changes, you can use [Github's editing feature](https://help.github.com/articles/editing-files-in-another-user-s-repository/). The only thing to keep in mind is to prefix the commit message with "docs: ". -The detault commit message generated by Github will lead to a failing CI build. +The default commit message generated by Github will lead to a failing CI build. For larger updates to the documentation it might be better to follow the [instructions for contributing code below](#contributing-code). diff --git a/lib/assertive.js b/lib/assertive.js index 4634242..3eb6c0d 100644 --- a/lib/assertive.js +++ b/lib/assertive.js @@ -1,9 +1,3 @@ -'use strict'; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - /* * Copyright (c) 2013, Groupon, Inc. * All rights reserved. @@ -35,40 +29,16 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* -Copyright (c) 2013, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + +'use strict'; // eat _ off the global scope, or require it ourselves if missing // eslint-disable-next-line no-new-func + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + var global = Function('return this')(); var assert = void 0; @@ -371,7 +341,7 @@ var assertSync = { if (negated) { if (contained) { // eslint-disable-next-line prefer-template - var message = 'notInclude expected needle not to be found in ' + ('haystack\n- needle: ' + stringify(needle) + '\n haystack: ') + abbreviate('', haystack); + var message = '' + ('notInclude expected needle not to be found in ' + ('haystack\n- needle: ' + stringify(needle) + '\n haystack: ')) + abbreviate('', haystack); if (_.isString(haystack) && _.isRegExp(needle)) { message += ', but found:\n'; if (needle.global) { diff --git a/lib/assertive.js.map b/lib/assertive.js.map index f7b8353..cbf79cd 100644 --- a/lib/assertive.js.map +++ b/lib/assertive.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/assertive.js"],"names":["global","Function","assert","_","require","jsDiff","toString","Object","prototype","green","x","red","clear","process","stdout","isTTY","error","message","explanation","Error","nameNegative","name","charAt","toUpperCase","slice","asRegExp","re","flags","multiline","ignoreCase","source","stringifyReplacer","key","val","isRegExp","isObject","isArray","toPairs","sortBy","fromPairs","value","stringify","isNaN","json","JSON","className","constructor","test","stack","e","handleArgs","self","count","args","help","negated","isString","argc","length","max","indexOf","n","wantedArgCount","isNumber","join","pop","actualArgs","call","functionSource","wantedArgNames","match","wanted","actual","type","TypeError","abbreviate","threshold","str","desc","getNameOfType","isFunction","types","implodeNicely","list","conjunction","first","last","isType","typeName","isDate","getTypeName","find","partial","assertSync","truthy","bool","arguments","expect","equal","expected","deepEqual","isEqual","wrongLooks","rightLooks","values","diffJson","map","entry","prefix","added","removed","replace","include","needle","haystack","what","problem","contained","includes","s","regexp","string","oops","called","matched","throws","fn","undefined","err","hasType","expectedType","stringType","badArg","suggestions","typeMatches","toBeOrNotToBe","positiveAssertions","forEach","_oneTest","apply","isPromiseAlike","p","then","resolves","testee","identity","catch","rejects","module","exports"],"mappings":"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","file":"assertive.js","sourcesContent":["/*\n * Copyright (c) 2013, Groupon, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * Neither the name of GROUPON nor the names of its contributors may be\n * used to endorse or promote products derived from this software without\n * specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n/*\nCopyright (c) 2013, Groupon, Inc.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\nRedistributions of source code must retain the above copyright notice,\nthis list of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer in the\ndocumentation and/or other materials provided with the distribution.\n\nNeither the name of GROUPON nor the names of its contributors may be\nused to endorse or promote products derived from this software without\nspecific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\nIS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\nTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\nPARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n// eat _ off the global scope, or require it ourselves if missing\n// eslint-disable-next-line no-new-func\nconst global = Function('return this')();\nlet assert;\n\n// eslint-disable-next-line global-require\nconst _ = global._ || require('lodash');\n\n// may be stubbed out for browsers\nconst jsDiff = require('diff');\n\nconst toString = Object.prototype.toString;\n\nlet green = x => `\\x1B[32m${x}\\x1B[39m`;\nlet red = x => `\\x1B[31m${x}\\x1B[39m`;\nlet clear = '\\x1b[39;49;00m';\n\nif (!(global.process && process.stdout && process.stdout.isTTY)) {\n red = x => `${x}`;\n green = red;\n clear = '';\n}\n\nfunction error(message, explanation) {\n if (explanation != null) {\n message = `Assertion failed: ${explanation}\\n${clear}${message}`;\n }\n return new Error(message);\n}\n\nfunction nameNegative(name) {\n if (name === 'truthy') { return 'falsey'; }\n if (name === 'resolves') { return 'rejects'; }\n return `not${name.charAt().toUpperCase()}${name.slice(1)}`;\n}\n\nfunction asRegExp(re) {\n let flags = '';\n if (re.global) flags += 'g';\n if (re.multiline) flags += 'm';\n if (re.ignoreCase) flags += 'i';\n return `/${re.source}/${flags}`;\n}\n\nfunction stringifyReplacer(key, val) {\n if (typeof val === 'function') return toString(val);\n if (_.isRegExp(val)) return asRegExp(val);\n if (_.isObject(val) && !_.isArray(val)) {\n return _(val).toPairs().sortBy(0).fromPairs()\n .value();\n }\n return val;\n}\n\nfunction stringify(x) {\n if (x == null) return `${x}`;\n if (_.isNaN(x)) return 'NaN';\n if (_.isRegExp(x)) return asRegExp(x);\n if (typeof x === 'symbol') return x.toString();\n const json = JSON.stringify(x, stringifyReplacer, 2);\n const className = x && x.constructor && x.constructor.name;\n if (typeof x !== 'object' || className === 'Object' || className === 'Array') {\n return json;\n }\n\n if (x instanceof Error || /Error/.test(className)) {\n if (json === '{}') { return x.stack; }\n return `${x.stack}\\nwith error metadata:\\n${json}`;\n }\n if (x.toString === toString) { return className; }\n try {\n return `${className}[${x}]`;\n } catch (e) {\n return className;\n }\n}\n\n// assert that the function got `count` args (if an integer), one of the number\n// of args (if an array of legal counts), and if it was an array and the count\n// was equal to the last option (fully populated), that the first arg is a String\n// (that test's semantic explanation)\nfunction handleArgs(self, count, args, name, help) {\n let negated = false;\n if (_.isString(self)) {\n negated = true;\n name = nameNegative(name);\n }\n\n const argc = args.length;\n if (argc === count) return [name, negated];\n\n let max = '';\n if (_.isArray(count) && count.indexOf(argc) !== -1) {\n const n = count[count.length - 1];\n if ((argc !== n) || _.isString(args[0])) return [name, negated];\n max = `,\\nand when called with ${n} args, the first arg must be a docstring`;\n }\n\n let wantedArgCount;\n if (_.isNumber(count)) {\n wantedArgCount = `${count} argument`;\n } else {\n wantedArgCount = count.slice(0, -1).join(', ');\n count = count.pop();\n wantedArgCount = `${wantedArgCount} or ${count} argument`;\n }\n if (count !== 1) wantedArgCount += 's';\n\n const actualArgs = stringify([].slice.call(args)).slice(1, -1);\n\n const functionSource = Function.prototype.toString.call(assert[name]);\n let wantedArgNames = functionSource.match(/^function\\s*[^(]*\\s*\\(([^)]*)/)[1];\n if (max) { wantedArgNames = `explanation, ${wantedArgNames}`; }\n\n const wanted = `${name}(${wantedArgNames})`;\n const actual = `${name}(${actualArgs})`;\n const message = `${green(wanted)} needs ${wantedArgCount + max}\nyour usage: ${red(actual)}`;\n\n if (typeof help === 'function') { help = help(); }\n throw error(message, help);\n}\n\nfunction type(x) {\n if (_.isString(x)) return 'String';\n if (_.isNumber(x)) return 'Number';\n if (_.isRegExp(x)) return 'RegExp';\n if (_.isArray(x)) return 'Array';\n throw new TypeError(`unsupported type: ${x}`);\n}\n\nfunction abbreviate(name, value, threshold) {\n const str = stringify(value);\n if (str.length <= (threshold || 1024)) return str;\n let desc = `length: ${value.length}`;\n if (_.isArray(value)) desc += `; ${str.length} JSON encoded`;\n if (name) name += ' ';\n return `${name}${type(value)}[${desc}]`;\n}\n\n// translates any argument we were meant to interpret as a type, into its name\nfunction getNameOfType(x) {\n switch (false) {\n case !(x == null): return `${x}`; // null / undefined\n case !_.isString(x): return x;\n case !_.isFunction(x): return x.name;\n case !_.isNaN(x): return 'NaN';\n default: return x;\n }\n}\n\n// listing the most specific types first lets us iterate in order and verify that\n// the expected type was the first match\nconst types = [\n 'null',\n 'Date',\n 'Array',\n 'String',\n 'RegExp',\n 'Boolean',\n 'Function',\n 'Object',\n 'NaN',\n 'Number',\n 'undefined',\n];\n\nfunction implodeNicely(list, conjunction) {\n const first = list.slice(0, -1).join(', ');\n const last = list[list.length - 1];\n return `${first} ${conjunction || 'and'} ${last}`;\n}\n\nfunction isType(value, typeName) {\n if (typeName === 'Date') return _.isDate(value) && !_.isNaN(+value);\n return _[`is${typeName[0].toUpperCase()}${typeName.slice(1)}`](value);\n}\n\n// gets the name of the type that value is an incarnation of\nfunction getTypeName(value) {\n return _.find(types, _.partial(isType, value));\n}\n\n/* eslint-disable prefer-rest-params */\nconst assertSync = {\n truthy(bool) {\n const args = handleArgs(this, [1, 2], arguments, 'truthy');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 2) {\n explanation = arguments[0];\n bool = arguments[1];\n }\n if ((!bool && !negated) || (bool && negated)) {\n throw error(`Expected ${red(stringify(bool))} to be ${name}`, explanation);\n }\n },\n\n expect(bool) {\n let explanation;\n if (arguments.length === 2) {\n explanation = arguments[0];\n bool = arguments[1];\n }\n if (explanation) return assertSync.equal(explanation, true, bool);\n return assertSync.equal(true, bool);\n },\n\n equal(expected, actual) {\n let explanation;\n const negated = handleArgs(this, [2, 3], arguments, 'equal')[1];\n if (arguments.length === 3) {\n explanation = arguments[0];\n expected = arguments[1];\n actual = arguments[2];\n }\n if (negated) {\n if (expected === actual) {\n throw error(`notEqual assertion expected ${red(stringify(actual))}` +\n ' to be exactly anything else', explanation);\n }\n } else if (expected !== actual) {\n throw error(`Expected: ${green(stringify(expected))}\\nActually: ` +\n `${red(stringify(actual))}`, explanation);\n }\n },\n\n deepEqual(expected, actual) {\n let explanation;\n const negated = handleArgs(this, [2, 3], arguments, 'deepEqual')[1];\n if (arguments.length === 3) {\n explanation = arguments[0];\n expected = arguments[1];\n actual = arguments[2];\n }\n const isEqual = _.isEqual(expected, actual);\n if ((isEqual && !negated) || (!isEqual && negated)) return;\n\n const wrongLooks = stringify(actual);\n if (negated) {\n throw error(`notDeepEqual assertion expected exactly anything else but\n${red(wrongLooks)}`, explanation);\n }\n\n const rightLooks = stringify(expected);\n let message;\n if (wrongLooks === rightLooks) {\n message = `deepEqual ${green(rightLooks)} failed on something that\\n` +\n 'serializes to the same result (likely some function)';\n } else {\n const values = jsDiff.diffJson(actual, expected).map((entry) => {\n let value = entry.value;\n let prefix = ' ';\n if (entry.added) prefix = '+ ';\n else if (entry.removed) prefix = '- ';\n value = value.replace(/^/gm, prefix).replace(/\\n..$/, '');\n if (entry.added) value = green(value);\n else if (entry.removed) value = red(value);\n return value;\n });\n message =\n `Actual: ${red('-')} Expected: ${green('+')}\\n${values.join('\\n')}`;\n }\n\n throw error(message, explanation);\n },\n\n include(needle, haystack) {\n const args = handleArgs(this, [2, 3], arguments, 'include');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 3) {\n explanation = arguments[0];\n needle = arguments[1];\n haystack = arguments[2];\n }\n if (_.isString(haystack)) {\n if (needle === '') {\n const what = negated ? 'always-failing test' : 'no-op test';\n throw error(`${what} detected: all strings contain the empty string!`);\n }\n if (!_.isString(needle) && !_.isNumber(needle) && !_.isRegExp(needle)) {\n const problem = 'needs a RegExp/String/Number needle for a String haystack';\n throw new TypeError(\n `${name} ${problem}; you used:\\n` +\n `${name} ${green(stringify(haystack))}, ${red(stringify(needle))}`\n );\n }\n } else if (!_.isArray(haystack)) {\n needle = stringify(needle);\n throw new TypeError(`${name} takes a String or Array haystack; you used:\n${name} ${red(stringify(haystack))}, ${needle}`\n );\n }\n\n let contained;\n if (_.isString(haystack)) {\n if (_.isRegExp(needle)) {\n contained = haystack.match(needle);\n } else {\n contained = haystack.indexOf(needle) !== -1;\n }\n } else {\n contained = _.includes(haystack, needle);\n }\n\n if (negated) {\n if (contained) {\n // eslint-disable-next-line prefer-template\n let message = 'notInclude expected needle not to be found in ' +\n `haystack\\n- needle: ${stringify(needle)}\\n haystack: ` +\n abbreviate('', haystack);\n if (_.isString(haystack) && _.isRegExp(needle)) {\n message += ', but found:\\n';\n if (needle.global) {\n message += contained.map(s => `* ${red(stringify(s))}`).join('\\n');\n } else {\n message += `* ${red(stringify(contained[0]))}`;\n }\n }\n throw error(message, explanation);\n }\n } else if (!contained) {\n throw error(`${name} expected needle to be found in haystack\\n` +\n `- needle: ${stringify(needle)}\\n` +\n `haystack: ${abbreviate('', haystack)}`, explanation);\n }\n },\n\n match(regexp, string) {\n const args = handleArgs(this, [2, 3], arguments, 'match');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 3) {\n explanation = arguments[0];\n regexp = arguments[1];\n string = arguments[2];\n }\n\n const re = _.isRegExp(regexp);\n if (!re || !_.isString(string)) {\n string = abbreviate('string', string);\n const oops = re ? 'string arg is not a String'\n : 'regexp arg is not a RegExp';\n const called = `${name} ${stringify(regexp)}, ${red(string)}`;\n throw new TypeError(`${name}: ${oops}; you used:\\n${called}`);\n }\n\n const matched = regexp.test(string);\n if (negated) {\n if (!matched) return;\n let message = `Expected: ${stringify(regexp)}\\nnot to match: ` +\n `${red(abbreviate('string', string))}`;\n if (regexp.global) {\n const count = string.match(regexp).length;\n message += `\\nMatches: ${red(count)}`;\n }\n throw error(message, explanation);\n }\n if (!matched) {\n throw error(`Expected: ${stringify(regexp)}\\nto match: ` +\n `${red(abbreviate('string', string))}`, explanation);\n }\n },\n\n throws(fn) {\n const args = handleArgs(this, [1, 2], arguments, 'throws');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 2) {\n explanation = arguments[0];\n fn = arguments[1];\n }\n if (typeof explanation === 'function') {\n fn = explanation;\n explanation = undefined;\n }\n if (typeof fn !== 'function') {\n throw error(`${name} expects ${green('a function')} but got ${red(fn)}`);\n }\n\n try {\n fn();\n } catch (err) {\n if (negated) {\n throw error(`Threw an exception despite ${name} assertion:\\n` +\n `${err.message}`, explanation);\n }\n return err;\n }\n\n if (negated) return undefined;\n throw error(\"Didn't throw an exception as expected to\", explanation);\n },\n\n hasType(expectedType, value) {\n const args = handleArgs(this, [2, 3], arguments, 'hasType');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 3) {\n explanation = arguments[0];\n expectedType = arguments[1];\n value = arguments[2];\n }\n\n const stringType = getNameOfType(expectedType);\n if (types.indexOf(stringType) === -1) {\n const badArg = stringify(expectedType);\n const suggestions = implodeNicely(types, 'or');\n throw new TypeError(\n `${name}: unknown expectedType ${badArg}; you used:\\n${name} ` +\n `${red(badArg)}, ${stringify(value)}\\nDid you mean ${suggestions}?`\n );\n }\n\n const typeMatches = stringType === getTypeName(value);\n if ((!typeMatches && !negated) || (typeMatches && negated)) {\n value = red(stringify(value));\n const toBeOrNotToBe = `${negated ? 'not ' : ''}to be`;\n const message =\n `Expected value ${value} ${toBeOrNotToBe} of type ${stringType}`;\n throw error(message, explanation);\n }\n },\n};\n\n// produce negatived versions of all the common assertion functions\nconst positiveAssertions = [\n 'truthy',\n 'equal',\n 'deepEqual',\n 'include',\n 'match',\n 'throws',\n 'hasType',\n];\npositiveAssertions.forEach((name) => {\n assertSync[nameNegative(name)] = function _oneTest() {\n return assertSync[name].apply('!', arguments);\n };\n});\n\n// borrowed from Q\nfunction isPromiseAlike(p) {\n return p === Object(p) && (typeof p.then === 'function');\n}\n\n// promise-specific tests\nassert = {\n resolves(testee) {\n const name = handleArgs(this, [1, 2], arguments, 'resolves')[0];\n let explanation;\n if (arguments.length === 2) {\n explanation = arguments[0];\n testee = arguments[1];\n }\n\n if (!isPromiseAlike(testee)) {\n throw error(\n `${name} expects ${green('a promise')} but got ${red(stringify(testee))}`\n );\n }\n\n if (name === 'rejects') {\n return testee.then(\n (() => { throw error(\"Promise wasn't rejected as expected to\", explanation); }),\n _.identity\n );\n }\n return testee.catch((err) => {\n throw error('Promise was rejected despite resolves assertion:\\n' +\n `${(err && err.message) || err}`, explanation);\n });\n },\n\n rejects() { return assert.resolves.apply('!', arguments); },\n};\n\n// union of promise-specific and promise-aware wrapped synchronous tests\n_.forEach(assertSync || {}, (fn, name) => {\n assert[name] = function _oneTest() {\n if (arguments.length === 0) return fn();\n const args = [].slice.call(arguments);\n const testee = args.pop();\n if (isPromiseAlike(testee)) {\n return testee.then(val => fn(...args, val));\n }\n return fn(...args, testee);\n };\n});\n\n\n// export as a module to node - or to the global scope, if not\nif (typeof module !== 'undefined' && module && module.exports) {\n module.exports = assert;\n} else {\n global.assert = assert;\n}\n"]} \ No newline at end of file +{"version":3,"sources":["../src/assertive.js"],"names":["global","Function","assert","_","require","jsDiff","toString","Object","prototype","green","x","red","clear","process","stdout","isTTY","error","message","explanation","Error","nameNegative","name","charAt","toUpperCase","slice","asRegExp","re","flags","multiline","ignoreCase","source","stringifyReplacer","key","val","isRegExp","isObject","isArray","toPairs","sortBy","fromPairs","value","stringify","isNaN","json","JSON","className","constructor","test","stack","e","handleArgs","self","count","args","help","negated","isString","argc","length","max","indexOf","n","wantedArgCount","isNumber","join","pop","actualArgs","call","functionSource","wantedArgNames","match","wanted","actual","type","TypeError","abbreviate","threshold","str","desc","getNameOfType","isFunction","types","implodeNicely","list","conjunction","first","last","isType","typeName","isDate","getTypeName","find","partial","assertSync","truthy","bool","arguments","expect","equal","expected","deepEqual","isEqual","wrongLooks","rightLooks","values","diffJson","map","entry","prefix","added","removed","replace","include","needle","haystack","what","problem","contained","includes","s","regexp","string","oops","called","matched","throws","fn","undefined","err","hasType","expectedType","stringType","badArg","suggestions","typeMatches","toBeOrNotToBe","positiveAssertions","forEach","_oneTest","apply","isPromiseAlike","p","then","resolves","testee","identity","catch","rejects","module","exports"],"mappings":"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","file":"assertive.js","sourcesContent":["/*\n * Copyright (c) 2013, Groupon, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * Neither the name of GROUPON nor the names of its contributors may be\n * used to endorse or promote products derived from this software without\n * specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n'use strict';\n\n// eat _ off the global scope, or require it ourselves if missing\n// eslint-disable-next-line no-new-func\nconst global = Function('return this')();\nlet assert;\n\n// eslint-disable-next-line global-require\nconst _ = global._ || require('lodash');\n\n// may be stubbed out for browsers\nconst jsDiff = require('diff');\n\nconst toString = Object.prototype.toString;\n\nlet green = x => `\\x1B[32m${x}\\x1B[39m`;\nlet red = x => `\\x1B[31m${x}\\x1B[39m`;\nlet clear = '\\x1b[39;49;00m';\n\nif (!(global.process && process.stdout && process.stdout.isTTY)) {\n red = x => `${x}`;\n green = red;\n clear = '';\n}\n\nfunction error(message, explanation) {\n if (explanation != null) {\n message = `Assertion failed: ${explanation}\\n${clear}${message}`;\n }\n return new Error(message);\n}\n\nfunction nameNegative(name) {\n if (name === 'truthy') {\n return 'falsey';\n }\n if (name === 'resolves') {\n return 'rejects';\n }\n return `not${name.charAt().toUpperCase()}${name.slice(1)}`;\n}\n\nfunction asRegExp(re) {\n let flags = '';\n if (re.global) flags += 'g';\n if (re.multiline) flags += 'm';\n if (re.ignoreCase) flags += 'i';\n return `/${re.source}/${flags}`;\n}\n\nfunction stringifyReplacer(key, val) {\n if (typeof val === 'function') return toString(val);\n if (_.isRegExp(val)) return asRegExp(val);\n if (_.isObject(val) && !_.isArray(val)) {\n return _(val)\n .toPairs()\n .sortBy(0)\n .fromPairs()\n .value();\n }\n return val;\n}\n\nfunction stringify(x) {\n if (x == null) return `${x}`;\n if (_.isNaN(x)) return 'NaN';\n if (_.isRegExp(x)) return asRegExp(x);\n if (typeof x === 'symbol') return x.toString();\n const json = JSON.stringify(x, stringifyReplacer, 2);\n const className = x && x.constructor && x.constructor.name;\n if (\n typeof x !== 'object' ||\n className === 'Object' ||\n className === 'Array'\n ) {\n return json;\n }\n\n if (x instanceof Error || /Error/.test(className)) {\n if (json === '{}') {\n return x.stack;\n }\n return `${x.stack}\\nwith error metadata:\\n${json}`;\n }\n if (x.toString === toString) {\n return className;\n }\n try {\n return `${className}[${x}]`;\n } catch (e) {\n return className;\n }\n}\n\n// assert that the function got `count` args (if an integer), one of the number\n// of args (if an array of legal counts), and if it was an array and the count\n// was equal to the last option (fully populated), that the first arg is a String\n// (that test's semantic explanation)\nfunction handleArgs(self, count, args, name, help) {\n let negated = false;\n if (_.isString(self)) {\n negated = true;\n name = nameNegative(name);\n }\n\n const argc = args.length;\n if (argc === count) return [name, negated];\n\n let max = '';\n if (_.isArray(count) && count.indexOf(argc) !== -1) {\n const n = count[count.length - 1];\n if (argc !== n || _.isString(args[0])) return [name, negated];\n max = `,\\nand when called with ${\n n\n } args, the first arg must be a docstring`;\n }\n\n let wantedArgCount;\n if (_.isNumber(count)) {\n wantedArgCount = `${count} argument`;\n } else {\n wantedArgCount = count.slice(0, -1).join(', ');\n count = count.pop();\n wantedArgCount = `${wantedArgCount} or ${count} argument`;\n }\n if (count !== 1) wantedArgCount += 's';\n\n const actualArgs = stringify([].slice.call(args)).slice(1, -1);\n\n const functionSource = Function.prototype.toString.call(assert[name]);\n let wantedArgNames = functionSource.match(/^function\\s*[^(]*\\s*\\(([^)]*)/)[1];\n if (max) {\n wantedArgNames = `explanation, ${wantedArgNames}`;\n }\n\n const wanted = `${name}(${wantedArgNames})`;\n const actual = `${name}(${actualArgs})`;\n const message = `${green(wanted)} needs ${wantedArgCount + max}\nyour usage: ${red(actual)}`;\n\n if (typeof help === 'function') {\n help = help();\n }\n throw error(message, help);\n}\n\nfunction type(x) {\n if (_.isString(x)) return 'String';\n if (_.isNumber(x)) return 'Number';\n if (_.isRegExp(x)) return 'RegExp';\n if (_.isArray(x)) return 'Array';\n throw new TypeError(`unsupported type: ${x}`);\n}\n\nfunction abbreviate(name, value, threshold) {\n const str = stringify(value);\n if (str.length <= (threshold || 1024)) return str;\n let desc = `length: ${value.length}`;\n if (_.isArray(value)) desc += `; ${str.length} JSON encoded`;\n if (name) name += ' ';\n return `${name}${type(value)}[${desc}]`;\n}\n\n// translates any argument we were meant to interpret as a type, into its name\nfunction getNameOfType(x) {\n switch (false) {\n case !(x == null):\n return `${x}`; // null / undefined\n case !_.isString(x):\n return x;\n case !_.isFunction(x):\n return x.name;\n case !_.isNaN(x):\n return 'NaN';\n default:\n return x;\n }\n}\n\n// listing the most specific types first lets us iterate in order and verify that\n// the expected type was the first match\nconst types = [\n 'null',\n 'Date',\n 'Array',\n 'String',\n 'RegExp',\n 'Boolean',\n 'Function',\n 'Object',\n 'NaN',\n 'Number',\n 'undefined',\n];\n\nfunction implodeNicely(list, conjunction) {\n const first = list.slice(0, -1).join(', ');\n const last = list[list.length - 1];\n return `${first} ${conjunction || 'and'} ${last}`;\n}\n\nfunction isType(value, typeName) {\n if (typeName === 'Date') return _.isDate(value) && !_.isNaN(+value);\n return _[`is${typeName[0].toUpperCase()}${typeName.slice(1)}`](value);\n}\n\n// gets the name of the type that value is an incarnation of\nfunction getTypeName(value) {\n return _.find(types, _.partial(isType, value));\n}\n\n/* eslint-disable prefer-rest-params */\nconst assertSync = {\n truthy(bool) {\n const args = handleArgs(this, [1, 2], arguments, 'truthy');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 2) {\n explanation = arguments[0];\n bool = arguments[1];\n }\n if ((!bool && !negated) || (bool && negated)) {\n throw error(\n `Expected ${red(stringify(bool))} to be ${name}`,\n explanation\n );\n }\n },\n\n expect(bool) {\n let explanation;\n if (arguments.length === 2) {\n explanation = arguments[0];\n bool = arguments[1];\n }\n if (explanation) return assertSync.equal(explanation, true, bool);\n return assertSync.equal(true, bool);\n },\n\n equal(expected, actual) {\n let explanation;\n const negated = handleArgs(this, [2, 3], arguments, 'equal')[1];\n if (arguments.length === 3) {\n explanation = arguments[0];\n expected = arguments[1];\n actual = arguments[2];\n }\n if (negated) {\n if (expected === actual) {\n throw error(\n `notEqual assertion expected ${red(stringify(actual))}` +\n ' to be exactly anything else',\n explanation\n );\n }\n } else if (expected !== actual) {\n throw error(\n `Expected: ${green(stringify(expected))}\\nActually: ` +\n `${red(stringify(actual))}`,\n explanation\n );\n }\n },\n\n deepEqual(expected, actual) {\n let explanation;\n const negated = handleArgs(this, [2, 3], arguments, 'deepEqual')[1];\n if (arguments.length === 3) {\n explanation = arguments[0];\n expected = arguments[1];\n actual = arguments[2];\n }\n const isEqual = _.isEqual(expected, actual);\n if ((isEqual && !negated) || (!isEqual && negated)) return;\n\n const wrongLooks = stringify(actual);\n if (negated) {\n throw error(\n `notDeepEqual assertion expected exactly anything else but\n${red(wrongLooks)}`,\n explanation\n );\n }\n\n const rightLooks = stringify(expected);\n let message;\n if (wrongLooks === rightLooks) {\n message =\n `deepEqual ${green(rightLooks)} failed on something that\\n` +\n 'serializes to the same result (likely some function)';\n } else {\n const values = jsDiff.diffJson(actual, expected).map(entry => {\n let value = entry.value;\n let prefix = ' ';\n if (entry.added) prefix = '+ ';\n else if (entry.removed) prefix = '- ';\n value = value.replace(/^/gm, prefix).replace(/\\n..$/, '');\n if (entry.added) value = green(value);\n else if (entry.removed) value = red(value);\n return value;\n });\n message = `Actual: ${red('-')} Expected: ${green('+')}\\n${values.join(\n '\\n'\n )}`;\n }\n\n throw error(message, explanation);\n },\n\n include(needle, haystack) {\n const args = handleArgs(this, [2, 3], arguments, 'include');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 3) {\n explanation = arguments[0];\n needle = arguments[1];\n haystack = arguments[2];\n }\n if (_.isString(haystack)) {\n if (needle === '') {\n const what = negated ? 'always-failing test' : 'no-op test';\n throw error(`${what} detected: all strings contain the empty string!`);\n }\n if (!_.isString(needle) && !_.isNumber(needle) && !_.isRegExp(needle)) {\n const problem =\n 'needs a RegExp/String/Number needle for a String haystack';\n throw new TypeError(\n `${name} ${problem}; you used:\\n` +\n `${name} ${green(stringify(haystack))}, ${red(stringify(needle))}`\n );\n }\n } else if (!_.isArray(haystack)) {\n needle = stringify(needle);\n throw new TypeError(`${name} takes a String or Array haystack; you used:\n${name} ${red(stringify(haystack))}, ${needle}`);\n }\n\n let contained;\n if (_.isString(haystack)) {\n if (_.isRegExp(needle)) {\n contained = haystack.match(needle);\n } else {\n contained = haystack.indexOf(needle) !== -1;\n }\n } else {\n contained = _.includes(haystack, needle);\n }\n\n if (negated) {\n if (contained) {\n // eslint-disable-next-line prefer-template\n let message = `${'notInclude expected needle not to be found in ' +\n `haystack\\n- needle: ${stringify(needle)}\\n haystack: `}${abbreviate(\n '',\n haystack\n )}`;\n if (_.isString(haystack) && _.isRegExp(needle)) {\n message += ', but found:\\n';\n if (needle.global) {\n message += contained.map(s => `* ${red(stringify(s))}`).join('\\n');\n } else {\n message += `* ${red(stringify(contained[0]))}`;\n }\n }\n throw error(message, explanation);\n }\n } else if (!contained) {\n throw error(\n `${name} expected needle to be found in haystack\\n` +\n `- needle: ${stringify(needle)}\\n` +\n `haystack: ${abbreviate('', haystack)}`,\n explanation\n );\n }\n },\n\n match(regexp, string) {\n const args = handleArgs(this, [2, 3], arguments, 'match');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 3) {\n explanation = arguments[0];\n regexp = arguments[1];\n string = arguments[2];\n }\n\n const re = _.isRegExp(regexp);\n if (!re || !_.isString(string)) {\n string = abbreviate('string', string);\n const oops = re\n ? 'string arg is not a String'\n : 'regexp arg is not a RegExp';\n const called = `${name} ${stringify(regexp)}, ${red(string)}`;\n throw new TypeError(`${name}: ${oops}; you used:\\n${called}`);\n }\n\n const matched = regexp.test(string);\n if (negated) {\n if (!matched) return;\n let message =\n `Expected: ${stringify(regexp)}\\nnot to match: ` +\n `${red(abbreviate('string', string))}`;\n if (regexp.global) {\n const count = string.match(regexp).length;\n message += `\\nMatches: ${red(count)}`;\n }\n throw error(message, explanation);\n }\n if (!matched) {\n throw error(\n `Expected: ${stringify(regexp)}\\nto match: ` +\n `${red(abbreviate('string', string))}`,\n explanation\n );\n }\n },\n\n throws(fn) {\n const args = handleArgs(this, [1, 2], arguments, 'throws');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 2) {\n explanation = arguments[0];\n fn = arguments[1];\n }\n if (typeof explanation === 'function') {\n fn = explanation;\n explanation = undefined;\n }\n if (typeof fn !== 'function') {\n throw error(`${name} expects ${green('a function')} but got ${red(fn)}`);\n }\n\n try {\n fn();\n } catch (err) {\n if (negated) {\n throw error(\n `Threw an exception despite ${name} assertion:\\n` + `${err.message}`,\n explanation\n );\n }\n return err;\n }\n\n if (negated) return undefined;\n throw error(\"Didn't throw an exception as expected to\", explanation);\n },\n\n hasType(expectedType, value) {\n const args = handleArgs(this, [2, 3], arguments, 'hasType');\n const name = args[0];\n const negated = args[1];\n let explanation;\n if (arguments.length === 3) {\n explanation = arguments[0];\n expectedType = arguments[1];\n value = arguments[2];\n }\n\n const stringType = getNameOfType(expectedType);\n if (types.indexOf(stringType) === -1) {\n const badArg = stringify(expectedType);\n const suggestions = implodeNicely(types, 'or');\n throw new TypeError(\n `${name}: unknown expectedType ${badArg}; you used:\\n${name} ` +\n `${red(badArg)}, ${stringify(value)}\\nDid you mean ${suggestions}?`\n );\n }\n\n const typeMatches = stringType === getTypeName(value);\n if ((!typeMatches && !negated) || (typeMatches && negated)) {\n value = red(stringify(value));\n const toBeOrNotToBe = `${negated ? 'not ' : ''}to be`;\n const message = `Expected value ${value} ${toBeOrNotToBe} of type ${\n stringType\n }`;\n throw error(message, explanation);\n }\n },\n};\n\n// produce negatived versions of all the common assertion functions\nconst positiveAssertions = [\n 'truthy',\n 'equal',\n 'deepEqual',\n 'include',\n 'match',\n 'throws',\n 'hasType',\n];\npositiveAssertions.forEach(name => {\n assertSync[nameNegative(name)] = function _oneTest() {\n return assertSync[name].apply('!', arguments);\n };\n});\n\n// borrowed from Q\nfunction isPromiseAlike(p) {\n return p === Object(p) && typeof p.then === 'function';\n}\n\n// promise-specific tests\nassert = {\n resolves(testee) {\n const name = handleArgs(this, [1, 2], arguments, 'resolves')[0];\n let explanation;\n if (arguments.length === 2) {\n explanation = arguments[0];\n testee = arguments[1];\n }\n\n if (!isPromiseAlike(testee)) {\n throw error(\n `${name} expects ${green('a promise')} but got ${red(\n stringify(testee)\n )}`\n );\n }\n\n if (name === 'rejects') {\n return testee.then(() => {\n throw error(\"Promise wasn't rejected as expected to\", explanation);\n }, _.identity);\n }\n return testee.catch(err => {\n throw error(\n 'Promise was rejected despite resolves assertion:\\n' +\n `${(err && err.message) || err}`,\n explanation\n );\n });\n },\n\n rejects() {\n return assert.resolves.apply('!', arguments);\n },\n};\n\n// union of promise-specific and promise-aware wrapped synchronous tests\n_.forEach(assertSync || {}, (fn, name) => {\n assert[name] = function _oneTest() {\n if (arguments.length === 0) return fn();\n const args = [].slice.call(arguments);\n const testee = args.pop();\n if (isPromiseAlike(testee)) {\n return testee.then(val => fn(...args, val));\n }\n return fn(...args, testee);\n };\n});\n\n// export as a module to node - or to the global scope, if not\nif (typeof module !== 'undefined' && module && module.exports) {\n module.exports = assert;\n} else {\n global.assert = assert;\n}\n"]} \ No newline at end of file diff --git a/lib/diff-stub.js b/lib/diff-stub.js index 32758a9..c413cc0 100644 --- a/lib/diff-stub.js +++ b/lib/diff-stub.js @@ -1,5 +1,3 @@ -"use strict"; - /* * Copyright (c) 2013, Groupon, Inc. * All rights reserved. @@ -31,7 +29,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +'use strict'; + // can't require('diff') properly with browserify, so just fall back on this + function diffJson(a, b) { return [{ removed: true, value: JSON.stringify(a, null, 2) }, { added: true, value: JSON.stringify(b, null, 2) }]; } diff --git a/lib/diff-stub.js.map b/lib/diff-stub.js.map index 1357400..b66fd7c 100644 --- a/lib/diff-stub.js.map +++ b/lib/diff-stub.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/diff-stub.js"],"names":["diffJson","a","b","removed","value","JSON","stringify","added","exports"],"mappings":";;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA;AACA,SAASA,QAAT,CAAkBC,CAAlB,EAAqBC,CAArB,EAAwB;AACtB,SAAO,CACL,EAAEC,SAAS,IAAX,EAAiBC,OAAOC,KAAKC,SAAL,CAAeL,CAAf,EAAkB,IAAlB,EAAwB,CAAxB,CAAxB,EADK,EAEL,EAAEM,OAAO,IAAT,EAAeH,OAAOC,KAAKC,SAAL,CAAeJ,CAAf,EAAkB,IAAlB,EAAwB,CAAxB,CAAtB,EAFK,CAAP;AAID;AACDM,QAAQR,QAAR,GAAmBA,QAAnB","file":"diff-stub.js","sourcesContent":["/*\n * Copyright (c) 2013, Groupon, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * Neither the name of GROUPON nor the names of its contributors may be\n * used to endorse or promote products derived from this software without\n * specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n// can't require('diff') properly with browserify, so just fall back on this\nfunction diffJson(a, b) {\n return [\n { removed: true, value: JSON.stringify(a, null, 2) },\n { added: true, value: JSON.stringify(b, null, 2) },\n ];\n}\nexports.diffJson = diffJson;\n"]} \ No newline at end of file +{"version":3,"sources":["../src/diff-stub.js"],"names":["diffJson","a","b","removed","value","JSON","stringify","added","exports"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA;;AAEA;;AACA,SAASA,QAAT,CAAkBC,CAAlB,EAAqBC,CAArB,EAAwB;AACtB,SAAO,CACL,EAAEC,SAAS,IAAX,EAAiBC,OAAOC,KAAKC,SAAL,CAAeL,CAAf,EAAkB,IAAlB,EAAwB,CAAxB,CAAxB,EADK,EAEL,EAAEM,OAAO,IAAT,EAAeH,OAAOC,KAAKC,SAAL,CAAeJ,CAAf,EAAkB,IAAlB,EAAwB,CAAxB,CAAtB,EAFK,CAAP;AAID;AACDM,QAAQR,QAAR,GAAmBA,QAAnB","file":"diff-stub.js","sourcesContent":["/*\n * Copyright (c) 2013, Groupon, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * Neither the name of GROUPON nor the names of its contributors may be\n * used to endorse or promote products derived from this software without\n * specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n'use strict';\n\n// can't require('diff') properly with browserify, so just fall back on this\nfunction diffJson(a, b) {\n return [\n { removed: true, value: JSON.stringify(a, null, 2) },\n { added: true, value: JSON.stringify(b, null, 2) },\n ];\n}\nexports.diffJson = diffJson;\n"]} \ No newline at end of file diff --git a/package.json b/package.json index 12339dd..a0da28d 100644 --- a/package.json +++ b/package.json @@ -36,14 +36,14 @@ "babel-cli": "^6.24.1", "babel-preset-env": "^1.6.0", "bluebird": "^3.3.4", - "eslint": "^3.0.0", - "eslint-config-groupon": "^4.0.0", - "eslint-config-groupon-node4": "^4.0.0", - "eslint-plugin-import": "^2.2.0", - "eslint-plugin-node": "^2.0.0", + "eslint": "^4.7.1", + "eslint-config-groupon": "^5.0.0", + "eslint-plugin-import": "^2.8.0", + "eslint-plugin-node": "^5.1.1", + "eslint-plugin-prettier": "^2.2.0", "mocha": "^3.1.2", "nlm": "^3.0.0", - "nodemon": "^1.0.0" + "prettier": "^1.6.1" }, "author": { "name": "Groupon", diff --git a/src/assertive.js b/src/assertive.js index 17f3bcc..98e8747 100644 --- a/src/assertive.js +++ b/src/assertive.js @@ -29,37 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* -Copyright (c) 2013, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + +'use strict'; // eat _ off the global scope, or require it ourselves if missing // eslint-disable-next-line no-new-func @@ -92,8 +63,12 @@ function error(message, explanation) { } function nameNegative(name) { - if (name === 'truthy') { return 'falsey'; } - if (name === 'resolves') { return 'rejects'; } + if (name === 'truthy') { + return 'falsey'; + } + if (name === 'resolves') { + return 'rejects'; + } return `not${name.charAt().toUpperCase()}${name.slice(1)}`; } @@ -109,7 +84,10 @@ function stringifyReplacer(key, val) { if (typeof val === 'function') return toString(val); if (_.isRegExp(val)) return asRegExp(val); if (_.isObject(val) && !_.isArray(val)) { - return _(val).toPairs().sortBy(0).fromPairs() + return _(val) + .toPairs() + .sortBy(0) + .fromPairs() .value(); } return val; @@ -122,15 +100,23 @@ function stringify(x) { if (typeof x === 'symbol') return x.toString(); const json = JSON.stringify(x, stringifyReplacer, 2); const className = x && x.constructor && x.constructor.name; - if (typeof x !== 'object' || className === 'Object' || className === 'Array') { + if ( + typeof x !== 'object' || + className === 'Object' || + className === 'Array' + ) { return json; } if (x instanceof Error || /Error/.test(className)) { - if (json === '{}') { return x.stack; } + if (json === '{}') { + return x.stack; + } return `${x.stack}\nwith error metadata:\n${json}`; } - if (x.toString === toString) { return className; } + if (x.toString === toString) { + return className; + } try { return `${className}[${x}]`; } catch (e) { @@ -155,8 +141,10 @@ function handleArgs(self, count, args, name, help) { let max = ''; if (_.isArray(count) && count.indexOf(argc) !== -1) { const n = count[count.length - 1]; - if ((argc !== n) || _.isString(args[0])) return [name, negated]; - max = `,\nand when called with ${n} args, the first arg must be a docstring`; + if (argc !== n || _.isString(args[0])) return [name, negated]; + max = `,\nand when called with ${ + n + } args, the first arg must be a docstring`; } let wantedArgCount; @@ -173,14 +161,18 @@ function handleArgs(self, count, args, name, help) { const functionSource = Function.prototype.toString.call(assert[name]); let wantedArgNames = functionSource.match(/^function\s*[^(]*\s*\(([^)]*)/)[1]; - if (max) { wantedArgNames = `explanation, ${wantedArgNames}`; } + if (max) { + wantedArgNames = `explanation, ${wantedArgNames}`; + } const wanted = `${name}(${wantedArgNames})`; const actual = `${name}(${actualArgs})`; const message = `${green(wanted)} needs ${wantedArgCount + max} your usage: ${red(actual)}`; - if (typeof help === 'function') { help = help(); } + if (typeof help === 'function') { + help = help(); + } throw error(message, help); } @@ -204,11 +196,16 @@ function abbreviate(name, value, threshold) { // translates any argument we were meant to interpret as a type, into its name function getNameOfType(x) { switch (false) { - case !(x == null): return `${x}`; // null / undefined - case !_.isString(x): return x; - case !_.isFunction(x): return x.name; - case !_.isNaN(x): return 'NaN'; - default: return x; + case !(x == null): + return `${x}`; // null / undefined + case !_.isString(x): + return x; + case !_.isFunction(x): + return x.name; + case !_.isNaN(x): + return 'NaN'; + default: + return x; } } @@ -256,7 +253,10 @@ const assertSync = { bool = arguments[1]; } if ((!bool && !negated) || (bool && negated)) { - throw error(`Expected ${red(stringify(bool))} to be ${name}`, explanation); + throw error( + `Expected ${red(stringify(bool))} to be ${name}`, + explanation + ); } }, @@ -280,12 +280,18 @@ const assertSync = { } if (negated) { if (expected === actual) { - throw error(`notEqual assertion expected ${red(stringify(actual))}` + - ' to be exactly anything else', explanation); + throw error( + `notEqual assertion expected ${red(stringify(actual))}` + + ' to be exactly anything else', + explanation + ); } } else if (expected !== actual) { - throw error(`Expected: ${green(stringify(expected))}\nActually: ` + - `${red(stringify(actual))}`, explanation); + throw error( + `Expected: ${green(stringify(expected))}\nActually: ` + + `${red(stringify(actual))}`, + explanation + ); } }, @@ -302,17 +308,21 @@ const assertSync = { const wrongLooks = stringify(actual); if (negated) { - throw error(`notDeepEqual assertion expected exactly anything else but -${red(wrongLooks)}`, explanation); + throw error( + `notDeepEqual assertion expected exactly anything else but +${red(wrongLooks)}`, + explanation + ); } const rightLooks = stringify(expected); let message; if (wrongLooks === rightLooks) { - message = `deepEqual ${green(rightLooks)} failed on something that\n` + + message = + `deepEqual ${green(rightLooks)} failed on something that\n` + 'serializes to the same result (likely some function)'; } else { - const values = jsDiff.diffJson(actual, expected).map((entry) => { + const values = jsDiff.diffJson(actual, expected).map(entry => { let value = entry.value; let prefix = ' '; if (entry.added) prefix = '+ '; @@ -322,8 +332,9 @@ ${red(wrongLooks)}`, explanation); else if (entry.removed) value = red(value); return value; }); - message = - `Actual: ${red('-')} Expected: ${green('+')}\n${values.join('\n')}`; + message = `Actual: ${red('-')} Expected: ${green('+')}\n${values.join( + '\n' + )}`; } throw error(message, explanation); @@ -345,17 +356,17 @@ ${red(wrongLooks)}`, explanation); throw error(`${what} detected: all strings contain the empty string!`); } if (!_.isString(needle) && !_.isNumber(needle) && !_.isRegExp(needle)) { - const problem = 'needs a RegExp/String/Number needle for a String haystack'; + const problem = + 'needs a RegExp/String/Number needle for a String haystack'; throw new TypeError( `${name} ${problem}; you used:\n` + - `${name} ${green(stringify(haystack))}, ${red(stringify(needle))}` + `${name} ${green(stringify(haystack))}, ${red(stringify(needle))}` ); } } else if (!_.isArray(haystack)) { needle = stringify(needle); throw new TypeError(`${name} takes a String or Array haystack; you used: -${name} ${red(stringify(haystack))}, ${needle}` - ); +${name} ${red(stringify(haystack))}, ${needle}`); } let contained; @@ -372,9 +383,11 @@ ${name} ${red(stringify(haystack))}, ${needle}` if (negated) { if (contained) { // eslint-disable-next-line prefer-template - let message = 'notInclude expected needle not to be found in ' + - `haystack\n- needle: ${stringify(needle)}\n haystack: ` + - abbreviate('', haystack); + let message = `${'notInclude expected needle not to be found in ' + + `haystack\n- needle: ${stringify(needle)}\n haystack: `}${abbreviate( + '', + haystack + )}`; if (_.isString(haystack) && _.isRegExp(needle)) { message += ', but found:\n'; if (needle.global) { @@ -386,9 +399,12 @@ ${name} ${red(stringify(haystack))}, ${needle}` throw error(message, explanation); } } else if (!contained) { - throw error(`${name} expected needle to be found in haystack\n` + - `- needle: ${stringify(needle)}\n` + - `haystack: ${abbreviate('', haystack)}`, explanation); + throw error( + `${name} expected needle to be found in haystack\n` + + `- needle: ${stringify(needle)}\n` + + `haystack: ${abbreviate('', haystack)}`, + explanation + ); } }, @@ -406,7 +422,8 @@ ${name} ${red(stringify(haystack))}, ${needle}` const re = _.isRegExp(regexp); if (!re || !_.isString(string)) { string = abbreviate('string', string); - const oops = re ? 'string arg is not a String' + const oops = re + ? 'string arg is not a String' : 'regexp arg is not a RegExp'; const called = `${name} ${stringify(regexp)}, ${red(string)}`; throw new TypeError(`${name}: ${oops}; you used:\n${called}`); @@ -415,7 +432,8 @@ ${name} ${red(stringify(haystack))}, ${needle}` const matched = regexp.test(string); if (negated) { if (!matched) return; - let message = `Expected: ${stringify(regexp)}\nnot to match: ` + + let message = + `Expected: ${stringify(regexp)}\nnot to match: ` + `${red(abbreviate('string', string))}`; if (regexp.global) { const count = string.match(regexp).length; @@ -424,8 +442,11 @@ ${name} ${red(stringify(haystack))}, ${needle}` throw error(message, explanation); } if (!matched) { - throw error(`Expected: ${stringify(regexp)}\nto match: ` + - `${red(abbreviate('string', string))}`, explanation); + throw error( + `Expected: ${stringify(regexp)}\nto match: ` + + `${red(abbreviate('string', string))}`, + explanation + ); } }, @@ -450,8 +471,10 @@ ${name} ${red(stringify(haystack))}, ${needle}` fn(); } catch (err) { if (negated) { - throw error(`Threw an exception despite ${name} assertion:\n` + - `${err.message}`, explanation); + throw error( + `Threw an exception despite ${name} assertion:\n` + `${err.message}`, + explanation + ); } return err; } @@ -477,7 +500,7 @@ ${name} ${red(stringify(haystack))}, ${needle}` const suggestions = implodeNicely(types, 'or'); throw new TypeError( `${name}: unknown expectedType ${badArg}; you used:\n${name} ` + - `${red(badArg)}, ${stringify(value)}\nDid you mean ${suggestions}?` + `${red(badArg)}, ${stringify(value)}\nDid you mean ${suggestions}?` ); } @@ -485,8 +508,9 @@ ${name} ${red(stringify(haystack))}, ${needle}` if ((!typeMatches && !negated) || (typeMatches && negated)) { value = red(stringify(value)); const toBeOrNotToBe = `${negated ? 'not ' : ''}to be`; - const message = - `Expected value ${value} ${toBeOrNotToBe} of type ${stringType}`; + const message = `Expected value ${value} ${toBeOrNotToBe} of type ${ + stringType + }`; throw error(message, explanation); } }, @@ -502,7 +526,7 @@ const positiveAssertions = [ 'throws', 'hasType', ]; -positiveAssertions.forEach((name) => { +positiveAssertions.forEach(name => { assertSync[nameNegative(name)] = function _oneTest() { return assertSync[name].apply('!', arguments); }; @@ -510,7 +534,7 @@ positiveAssertions.forEach((name) => { // borrowed from Q function isPromiseAlike(p) { - return p === Object(p) && (typeof p.then === 'function'); + return p === Object(p) && typeof p.then === 'function'; } // promise-specific tests @@ -525,23 +549,29 @@ assert = { if (!isPromiseAlike(testee)) { throw error( - `${name} expects ${green('a promise')} but got ${red(stringify(testee))}` + `${name} expects ${green('a promise')} but got ${red( + stringify(testee) + )}` ); } if (name === 'rejects') { - return testee.then( - (() => { throw error("Promise wasn't rejected as expected to", explanation); }), - _.identity - ); + return testee.then(() => { + throw error("Promise wasn't rejected as expected to", explanation); + }, _.identity); } - return testee.catch((err) => { - throw error('Promise was rejected despite resolves assertion:\n' + - `${(err && err.message) || err}`, explanation); + return testee.catch(err => { + throw error( + 'Promise was rejected despite resolves assertion:\n' + + `${(err && err.message) || err}`, + explanation + ); }); }, - rejects() { return assert.resolves.apply('!', arguments); }, + rejects() { + return assert.resolves.apply('!', arguments); + }, }; // union of promise-specific and promise-aware wrapped synchronous tests @@ -557,7 +587,6 @@ _.forEach(assertSync || {}, (fn, name) => { }; }); - // export as a module to node - or to the global scope, if not if (typeof module !== 'undefined' && module && module.exports) { module.exports = assert; diff --git a/src/diff-stub.js b/src/diff-stub.js index 689e05c..372fba9 100644 --- a/src/diff-stub.js +++ b/src/diff-stub.js @@ -29,6 +29,9 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +'use strict'; + // can't require('diff') properly with browserify, so just fall back on this function diffJson(a, b) { return [ diff --git a/test/.eslintrc b/test/.eslintrc index 365833e..292e610 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -1,5 +1,5 @@ { - "extends": "groupon-node4", + "extends": "groupon/node4", "env": { "mocha": true } diff --git a/test/assertive.test.js b/test/assertive.test.js index 351a07a..d66e61c 100644 --- a/test/assertive.test.js +++ b/test/assertive.test.js @@ -32,7 +32,10 @@ describe('throws', () => { it('notes that arg 1 must be a string when called with 2 args', () => { const err = throws(() => throws(1, 'description in wrong arg')); - include('called with 2 args, the first arg must be a docstring', err.message); + include( + 'called with 2 args, the first arg must be a docstring', + err.message + ); }); it('errors out unless you pass a function to execute', () => { @@ -42,9 +45,19 @@ describe('throws', () => { it('returns the exception that was thrown by the provided function', () => { const exception = new Error(68040); - equal(throws(() => { throw exception; }), exception); + equal( + throws(() => { + throw exception; + }), + exception + ); // eslint-disable-next-line no-throw-literal - equal(throws(() => { throw 'we suck'; }), 'we suck'); + equal( + throws(() => { + throw 'we suck'; + }), + 'we suck' + ); }); it('includes your helpful explanation, when provided', () => { @@ -54,7 +67,6 @@ describe('throws', () => { }); }); - describe('notThrows', () => { it('errors out when you provide too few or too many args', () => { throws(() => notThrows()); @@ -63,7 +75,10 @@ describe('notThrows', () => { it('notes that arg 1 must be a string when called with 2 args', () => { const err = throws(() => notThrows(1, 'description in wrong arg')); - include('called with 2 args, the first arg must be a docstring', err.message); + include( + 'called with 2 args, the first arg must be a docstring', + err.message + ); }); it('errors out unless you pass a function to execute', () => { @@ -73,15 +88,26 @@ describe('notThrows', () => { it('captures and shows exceptions thrown by the provided function', () => { const thrown = new Error(68040); - const caught = throws(() => notThrows(() => { throw thrown; })); - truthy('the exception thrown was caught and a new exception thrown', caught); + const caught = throws(() => + notThrows(() => { + throw thrown; + }) + ); + truthy( + 'the exception thrown was caught and a new exception thrown', + caught + ); include('Threw an exception despite notThrows assertion:', caught.message); include('assertion:\n68040', caught.message); }); it('includes your helpful explanation, when provided', () => { const explanation = 'No error was thrown - this is a problem'; - const err = throws(() => notThrows(explanation, () => { throw new Error('aiee!'); })); + const err = throws(() => + notThrows(explanation, () => { + throw new Error('aiee!'); + }) + ); include(explanation, err.message); }); }); @@ -120,11 +146,21 @@ function falseyOutcome(fn, outcome) { }; } -function truthyIsNoOp(fn) { return truthyOutcome(fn, notThrows); } -function falseyIsNoOp(fn) { return falseyOutcome(fn, notThrows); } -function truthyThrows(fn) { return truthyOutcome(fn, throws); } -function falseyThrows(fn) { return falseyOutcome(fn, throws); } -function nonTrueThrows(fn) { return nonTrueOutcome(fn, throws); } +function truthyIsNoOp(fn) { + return truthyOutcome(fn, notThrows); +} +function falseyIsNoOp(fn) { + return falseyOutcome(fn, notThrows); +} +function truthyThrows(fn) { + return truthyOutcome(fn, throws); +} +function falseyThrows(fn) { + return falseyOutcome(fn, throws); +} +function nonTrueThrows(fn) { + return nonTrueOutcome(fn, throws); +} describe('truthy', () => { it('errors out when you provide too few or too many args', () => { @@ -134,7 +170,10 @@ describe('truthy', () => { it('notes that arg 1 must be a string when called with 2 args', () => { const err = throws(() => truthy(true, 'description in wrong arg')); - include('called with 2 args, the first arg must be a docstring', err.message); + include( + 'called with 2 args, the first arg must be a docstring', + err.message + ); }); it("doesn't do anything when passed a truthy value", () => { @@ -144,13 +183,13 @@ describe('truthy', () => { it('errors out when passed a falsey value', falseyThrows(truthy)); it('includes your helpful explanation, when provided', () => { - const explanation = 'Given falsum, we can derive anything, which is awesome!'; + const explanation = + 'Given falsum, we can derive anything, which is awesome!'; const err = throws(() => truthy(explanation, false)); include(explanation, err.message); }); }); - describe('falsey', () => { it('errors out when you provide too few or too many args', () => { throws(() => falsey()); @@ -159,7 +198,10 @@ describe('falsey', () => { it('notes that arg 1 must be a string when called with 2 args', () => { const err = throws(() => falsey(false, 'description in wrong arg')); - include('called with 2 args, the first arg must be a docstring', err.message); + include( + 'called with 2 args, the first arg must be a docstring', + err.message + ); }); it("doesn't do anything when passed a falsey value", falseyIsNoOp(falsey)); @@ -173,7 +215,6 @@ describe('falsey', () => { }); }); - describe('expect', () => { it('errors out when you provide too few or way too many args', () => { throws(() => expect()); @@ -194,7 +235,6 @@ describe('expect', () => { }); }); - describe('equal', () => { it('errors out when you provide too few or too many args', () => { throws(() => equal()); @@ -204,7 +244,10 @@ describe('equal', () => { it('notes that arg 1 must be a string when called with 3 args', () => { const err = throws(() => equal(1, 1, 'description in wrong arg')); - include('called with 3 args, the first arg must be a docstring', err.message); + include( + 'called with 3 args, the first arg must be a docstring', + err.message + ); }); it("doesn't do anything when passed two identical values", function _oneTest() { @@ -223,7 +266,8 @@ describe('equal', () => { }); it('includes your helpful explanation, when provided', () => { - const explanation = 'Given falsum, we can derive anything, which is awesome!'; + const explanation = + 'Given falsum, we can derive anything, which is awesome!'; const err = throws(() => equal(explanation, 0, 1)); include(explanation, err.message); }); @@ -237,7 +281,6 @@ describe('equal', () => { } }); - describe('notEqual', () => { it('errors out when you provide too few or too many args', () => { throws(() => notEqual()); @@ -247,7 +290,10 @@ describe('notEqual', () => { it('notes that arg 1 must be a string when called with 3 args', () => { const err = throws(() => notEqual(1, 2, 'description in wrong arg')); - include('called with 3 args, the first arg must be a docstring', err.message); + include( + 'called with 3 args, the first arg must be a docstring', + err.message + ); }); it("doesn't do anything when passed two different values", function _oneTest() { @@ -259,7 +305,9 @@ describe('notEqual', () => { it('errors out when passed two identical values', () => { throws(() => notEqual(0, 0)); - throws(function shouldThrow() { return notEqual(this, this); }); + throws(function shouldThrow() { + return notEqual(this, this); + }); throws(() => notEqual(null, null)); throws(() => { const x = []; @@ -277,7 +325,6 @@ describe('notEqual', () => { }); }); - describe('deepEqual', () => { it('errors out when you provide too few or too many args', () => { throws(() => deepEqual()); @@ -287,7 +334,10 @@ describe('deepEqual', () => { it('notes that arg 1 must be a string when called with 3 args', () => { const err = throws(() => deepEqual(1, 1, 'description in wrong arg')); - include('called with 3 args, the first arg must be a docstring', err.message); + include( + 'called with 3 args, the first arg must be a docstring', + err.message + ); }); it("doesn't do anything when passed two deepEqual values", function _test() { @@ -313,7 +363,8 @@ describe('deepEqual', () => { }); it('includes your helpful explanation, when provided', () => { - const explanation = 'Given falsum, we can derive anything, which is awesome!'; + const explanation = + 'Given falsum, we can derive anything, which is awesome!'; const err = throws(() => deepEqual(explanation, [null], [undefined])); include(explanation, err.message); }); @@ -333,7 +384,10 @@ describe('notDeepEqual', () => { it('notes that arg 1 must be a string when called with 3 args', () => { const err = throws(() => notDeepEqual(1, 2, 'description in wrong arg')); - include('called with 3 args, the first arg must be a docstring', err.message); + include( + 'called with 3 args, the first arg must be a docstring', + err.message + ); }); it("doesn't do anything when passed two not deepEqual values", function _oneTest() { @@ -360,13 +414,13 @@ describe('notDeepEqual', () => { }); it('includes your helpful explanation, when provided', () => { - const explanation = 'Given falsum, we can derive anything, which is awesome!'; + const explanation = + 'Given falsum, we can derive anything, which is awesome!'; const err = throws(() => notDeepEqual(explanation, [null], [null])); include(explanation, err.message); }); }); - describe('include', () => { it('errors out when you provide too few or too many args', () => { throws(() => include()); @@ -376,20 +430,25 @@ describe('include', () => { it('notes that arg 1 must be a string when called with 3 args', () => { const err = throws(() => include(1, [1], 'description in wrong arg')); - include('called with 3 args, the first arg must be a docstring', err.message); + include( + 'called with 3 args, the first arg must be a docstring', + err.message + ); }); it('throws TypeErrors on bad needles', () => { const saneNeedlesPlease = /needs a .* needle for a String haystack/; let e = throws(() => include(undefined, 'undefined? baad')); match(saneNeedlesPlease, e.message); - e = throws(() => include((() => {}), 'function? worse')); + e = throws(() => include(() => {}, 'function? worse')); match(saneNeedlesPlease, e.message); truthy('should throw TypeError', e instanceof TypeError); }); it('throws an error for the no-op assertion string-contains-empty-string', () => { - const err = throws(() => include('', 'all strings include the empty string')); + const err = throws(() => + include('', 'all strings include the empty string') + ); const msg = 'no-op test detected: all strings contain the empty string!'; include(msg, err.message); }); @@ -427,16 +486,22 @@ describe('include', () => { it('errors out the same way when testing for a needle in an empty array', () => { const err = throws(() => include('not present in array', [])); - include(`include expected needle to be found in haystack + include( + `include expected needle to be found in haystack - needle: "not present in array" -haystack: []`, err.message); +haystack: []`, + err.message + ); }); it('errors out the same way when testing for a needle in an empty string', () => { const err = throws(() => include('not present in string', '')); - include(`include expected needle to be found in haystack + include( + `include expected needle to be found in haystack - needle: "not present in string" -haystack: ""`, err.message); +haystack: ""`, + err.message + ); }); it("errors out when the string passed doesn't match the RegExp", () => { @@ -452,18 +517,21 @@ haystack: ""`, err.message); }); it('includes your helpful explanation, when provided', () => { - const explanation = 'Given falsum, we can derive anything, which is awesome!'; + const explanation = + 'Given falsum, we can derive anything, which is awesome!'; const err = throws(() => include(explanation, [undefined], [null])); include(explanation, err.message); }); it('shortens larger haystacks in the assertion message', () => { const err = throws(() => include(2001, twoThousand)); - match(/^include [\s\S]*haystack: Array\[length: 2000; \d* JSON/, err.message); + match( + /^include [\s\S]*haystack: Array\[length: 2000; \d* JSON/, + err.message + ); }); }); - describe('notInclude', () => { it('errors out when you provide too few or too many args', () => { throws(() => notInclude()); @@ -480,7 +548,7 @@ describe('notInclude', () => { const saneNeedlesPlease = /needs a .* needle for a String haystack/; let e = throws(() => notInclude(undefined, 'undefined? baad')); match(saneNeedlesPlease, e.message); - e = throws(() => notInclude((() => {}), 'function? worse')); + e = throws(() => notInclude(() => {}, 'function? worse')); match(saneNeedlesPlease, e.message); truthy('should throw TypeError', e instanceof TypeError); }); @@ -492,8 +560,11 @@ describe('notInclude', () => { }); it('throws an error for the bad assertion string-lacks-empty-string', () => { - const err = throws(() => notInclude('', 'all strings include the empty string')); - const want = 'always-failing test detected: all strings contain the empty string!'; + const err = throws(() => + notInclude('', 'all strings include the empty string') + ); + const want = + 'always-failing test detected: all strings contain the empty string!'; include(want, err.message); }); @@ -532,13 +603,16 @@ describe('notInclude', () => { it('errors out when the array passed does include the value', () => { throws(() => notInclude(0, [0])); - throws(function shouldThrow() { return notInclude(this, [this]); }); + throws(function shouldThrow() { + return notInclude(this, [this]); + }); throws(() => notInclude(null, [null])); throws(() => notInclude(undefined, [undefined])); }); it('includes your helpful explanation, when provided', () => { - const explanation = 'Given falsum, we can derive anything, which is awesome!'; + const explanation = + 'Given falsum, we can derive anything, which is awesome!'; const err = throws(() => notInclude(explanation, null, [null])); include(explanation, err.message); }); @@ -549,7 +623,6 @@ describe('notInclude', () => { }); }); - describe('match', () => { it('errors out when you provide too few or too many args', () => { throws(() => match()); @@ -570,7 +643,10 @@ describe('match', () => { it('throws TypeErrors when called with a non-String', () => { const e = throws(() => match(/X/, undefined)); - match(/string arg is not a String; you used:\nmatch .*X.*undefin/, e.message); + match( + /string arg is not a String; you used:\nmatch .*X.*undefin/, + e.message + ); truthy('should throw TypeError', e instanceof TypeError); }); @@ -588,7 +664,8 @@ describe('match', () => { }); it('includes your helpful explanation, when provided', () => { - const explanation = 'Given falsum, we can derive anything, which is awesome!'; + const explanation = + 'Given falsum, we can derive anything, which is awesome!'; const e = throws(() => match(explanation, /aye/, 'nay')); include(explanation, e.message); }); @@ -599,7 +676,6 @@ describe('match', () => { }); }); - describe('notMatch', () => { it('errors out when you provide too few or too many args', () => { throws(() => notMatch()); @@ -620,17 +696,25 @@ describe('notMatch', () => { it('throws TypeErrors when called with a non-String', () => { const e = throws(() => notMatch(/x/, undefined)); - match(/string arg is not a String; you used:\nnotMatch.*undefine/, e.message); + match( + /string arg is not a String; you used:\nnotMatch.*undefine/, + e.message + ); truthy('should throw TypeError', e instanceof TypeError); }); - it("doesn't do anything when passed a RegExp not matching the string", () => notMatch(/^not/, 'FOOBAR')); + it("doesn't do anything when passed a RegExp not matching the string", () => + notMatch(/^not/, 'FOOBAR')); - it("doesn't break when also passed a docstring", () => notMatch('still fine and dandy', /^not/, 'FOOBAR')); + it("doesn't break when also passed a docstring", () => + notMatch('still fine and dandy', /^not/, 'FOOBAR')); it('errors out when the RegExp matches the passed string', () => { const e = throws(() => notMatch(/problem/i, 'Problems found!')); - match(/Expected: \/problem\/i\nnot to match: .*"Problems found!"/, e.message); + match( + /Expected: \/problem\/i\nnot to match: .*"Problems found!"/, + e.message + ); }); it('shows how many matches we did find when passed a global RegExp', () => { @@ -639,7 +723,8 @@ describe('notMatch', () => { }); it('includes your helpful explanation, when provided', () => { - const explanation = 'Given falsum, we can derive anything, which is awesome!'; + const explanation = + 'Given falsum, we can derive anything, which is awesome!'; const e = throws(() => notMatch(explanation, /woo/, 'woo!')); include(explanation, e.message); }); @@ -650,7 +735,6 @@ describe('notMatch', () => { }); }); - describe('hasType', () => { it('errors out when you provide too few, too many, or incorrect args', () => { throws(() => hasType()); @@ -703,8 +787,16 @@ describe('hasType', () => { it('recognizes Dates', () => { hasType(Date, new Date()); const invalidDate = new Date('Invalid Date'); - throws('Invalid Date tested as being a Date', () => hasType(Date, invalidDate)); - throws('Object tested as being a Date', () => hasType(Date, { getTime() { return 0; } })); + throws('Invalid Date tested as being a Date', () => + hasType(Date, invalidDate) + ); + throws('Object tested as being a Date', () => + hasType(Date, { + getTime() { + return 0; + }, + }) + ); }); it('recognizes null', () => { @@ -718,7 +810,6 @@ describe('hasType', () => { }); }); - describe('notHasType', () => { it('errors out when you provide too few, too many, or incorrect args', () => { throws(() => notHasType()); @@ -774,9 +865,15 @@ describe('notHasType', () => { }); it('recognizes non-Dates', () => { - notHasType(Date, { getTime() { return 0; } }); + notHasType(Date, { + getTime() { + return 0; + }, + }); notHasType(Date, new Date('Invalid Date')); - throws('Date tested as not being a Date', () => notHasType(Date, new Date())); + throws('Date tested as not being a Date', () => + notHasType(Date, new Date()) + ); }); it('recognizes not-null', () => { @@ -791,23 +888,31 @@ describe('notHasType', () => { }); describe('rejects', () => { - it('errors synchronously on non-promise', () => match(/^rejects expects/, throws(() => rejects(42)).message)); + it('errors synchronously on non-promise', () => + match(/^rejects expects/, throws(() => rejects(42)).message)); - it('resolves for a rejected promise', () => equal('kittens', rejects(Promise.reject('kittens')))); + it('resolves for a rejected promise', () => + equal('kittens', rejects(Promise.reject('kittens')))); it('rejects a resolved promise', () => - equal("Promise wasn't rejected as expected to", - rejects(rejects(Promise.resolve(42))).then(_.property('message'))) - ); + equal( + "Promise wasn't rejected as expected to", + rejects(rejects(Promise.resolve(42))).then(_.property('message')) + )); }); describe('resolves', () => { - it('errors synchronously on non-promise', () => match(/^resolves expects/, throws(() => resolves({})).message)); + it('errors synchronously on non-promise', () => + match(/^resolves expects/, throws(() => resolves({})).message)); it('rejects for a rejected promise', () => - include('Promise was rejected despite resolves assertion:\n42', - rejects(resolves(Promise.reject(new Error(42)))).then(_.property('message'))) - ); - - it('resolves for a resolved promise', () => equal('kittens', resolves(Promise.resolve('kittens')))); + include( + 'Promise was rejected despite resolves assertion:\n42', + rejects(resolves(Promise.reject(new Error(42)))).then( + _.property('message') + ) + )); + + it('resolves for a resolved promise', () => + equal('kittens', resolves(Promise.resolve('kittens')))); }); diff --git a/test/promisified.test.js b/test/promisified.test.js index c3db95d..ccd4687 100644 --- a/test/promisified.test.js +++ b/test/promisified.test.js @@ -9,7 +9,8 @@ const _ = require('lodash'); const syncFuncs = { truthy: { pass: { - args: [true], descr: 'a truthy promise resolution', + args: [true], + descr: 'a truthy promise resolution', }, fail: { args: [false], @@ -19,7 +20,9 @@ const syncFuncs = { }, equal: { - pass: { args: [5, 5], descr: 'an equal promise resolution', + pass: { + args: [5, 5], + descr: 'an equal promise resolution', }, fail: { args: [5, 6], @@ -53,7 +56,9 @@ const syncFuncs = { }, match: { - pass: { args: [/x/, 'fox'], descr: 'match /x/', + pass: { + args: [/x/, 'fox'], + descr: 'match /x/', }, fail: { args: [/x/, 'dog'], @@ -65,7 +70,11 @@ const syncFuncs = { throws: { pass: { // eslint-disable-next-line no-throw-literal - args: [() => { throw 'foo'; }], + args: [ + () => { + throw 'foo'; + }, + ], descr: 'a promise for an excepting function', }, fail: { @@ -82,7 +91,11 @@ const syncFuncs = { }, fail: { // eslint-disable-next-line no-throw-literal - args: [() => { throw 'foo'; }], + args: [ + () => { + throw 'foo'; + }, + ], descr: 'a promise for an excepting function', explain: 'function does not throw an exception', }, @@ -106,11 +119,12 @@ describe('promise-aware functionality', () => { const pass = bits.pass; const fail = bits.fail; - ['pass', 'fail'].forEach((pf) => { + ['pass', 'fail'].forEach(pf => { // replace last argument with promised resolution of same const args = bits[pf].args; - bits[pf].pargs = args.slice(0, args.length - 1).concat( - [Bluebird.resolve(args[args.length - 1])]); + bits[pf].pargs = args + .slice(0, args.length - 1) + .concat([Bluebird.resolve(args[args.length - 1])]); }); describe(name, () => { @@ -130,15 +144,15 @@ describe('promise-aware functionality', () => { assert.resolves( `${name} should succeed`, assert[name].apply(null, pass.pargs || []) - ) - ); + )); return it(`rejects for ${fail.descr}`, () => - assert.rejects( - `${name} should throw`, - assert[name].apply(null, [fail.explain].concat(fail.pargs)) - ).then(err => assert.include(fail.explain, err.message)) - ); + assert + .rejects( + `${name} should throw`, + assert[name].apply(null, [fail.explain].concat(fail.pargs)) + ) + .then(err => assert.include(fail.explain, err.message))); }); }); });