UNPKG

should

Version:

test framework agnostic BDD-style assertions

1,867 lines (1,664 loc) 83.6 kB
import getType from 'should-type'; import eql from 'should-equal'; import sformat from 'should-format'; import { defaultTypeAdaptorStorage, forEach, get, has, isEmpty, isIterable, iterator, size, some } from 'should-type-adaptors'; import { hasOwnProperty, isGeneratorFunction, isIterator, merge } from 'should-util'; /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ function isWrapperType(obj) { return obj instanceof Number || obj instanceof String || obj instanceof Boolean; } // XXX make it more strict: numbers, strings, symbols - and nothing else function convertPropertyName(name) { return typeof name === "symbol" ? name : String(name); } var functionName = sformat.functionName; function isPlainObject(obj) { if (typeof obj == "object" && obj !== null) { var proto = Object.getPrototypeOf(obj); return proto === Object.prototype || proto === null; } return false; } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ var config = { typeAdaptors: defaultTypeAdaptorStorage, getFormatter: function(opts) { return new sformat.Formatter(opts || config); } }; function format(value, opts) { return config.getFormatter(opts).format(value); } function formatProp(value) { var formatter = config.getFormatter(); return sformat.formatPlainObjectKey.call(formatter, value); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ /** * should AssertionError * @param {Object} options * @constructor * @memberOf should * @static */ function AssertionError(options) { merge(this, options); if (!options.message) { Object.defineProperty(this, "message", { get: function() { if (!this._message) { this._message = this.generateMessage(); this.generatedMessage = true; } return this._message; }, configurable: true, enumerable: false }); } if (Error.captureStackTrace) { Error.captureStackTrace(this, this.stackStartFunction); } else { // non v8 browsers so we can have a stacktrace var err = new Error(); if (err.stack) { var out = err.stack; if (this.stackStartFunction) { // try to strip useless frames var fn_name = functionName(this.stackStartFunction); var idx = out.indexOf("\n" + fn_name); if (idx >= 0) { // once we have located the function frame // we need to strip out everything before it (and its line) var next_line = out.indexOf("\n", idx + 1); out = out.substring(next_line + 1); } } this.stack = out; } } } var indent = " "; function prependIndent(line) { return indent + line; } function indentLines(text) { return text .split("\n") .map(prependIndent) .join("\n"); } // assert.AssertionError instanceof Error AssertionError.prototype = Object.create(Error.prototype, { name: { value: "AssertionError" }, generateMessage: { value: function() { if (!this.operator && this.previous) { return this.previous.message; } var actual = format(this.actual); var expected = "expected" in this ? " " + format(this.expected) : ""; var details = "details" in this && this.details ? " (" + this.details + ")" : ""; var previous = this.previous ? "\n" + indentLines(this.previous.message) : ""; return ( "expected " + actual + (this.negate ? " not " : " ") + this.operator + expected + details + previous ); } } }); /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ // a bit hacky way how to get error to do not have stack function LightAssertionError(options) { merge(this, options); if (!options.message) { Object.defineProperty(this, "message", { get: function() { if (!this._message) { this._message = this.generateMessage(); this.generatedMessage = true; } return this._message; } }); } } LightAssertionError.prototype = { generateMessage: AssertionError.prototype.generateMessage }; /** * should Assertion * @param {*} obj Given object for assertion * @constructor * @memberOf should * @static */ function Assertion(obj) { this.obj = obj; this.anyOne = false; this.negate = false; this.params = { actual: obj }; } Assertion.prototype = { constructor: Assertion, /** * Base method for assertions. * * Before calling this method need to fill Assertion#params object. This method usually called from other assertion methods. * `Assertion#params` can contain such properties: * * `operator` - required string containing description of this assertion * * `obj` - optional replacement for this.obj, it is useful if you prepare more clear object then given * * `message` - if this property filled with string any others will be ignored and this one used as assertion message * * `expected` - any object used when you need to assert relation between given object and expected. Like given == expected (== is a relation) * * `details` - additional string with details to generated message * * @memberOf Assertion * @category assertion * @param {*} expr Any expression that will be used as a condition for asserting. * @example * * var a = new should.Assertion(42); * * a.params = { * operator: 'to be magic number', * } * * a.assert(false); * //throws AssertionError: expected 42 to be magic number */ assert: function(expr) { if (expr) { return this; } var params = this.params; if ("obj" in params && !("actual" in params)) { params.actual = params.obj; } else if (!("obj" in params) && !("actual" in params)) { params.actual = this.obj; } params.stackStartFunction = params.stackStartFunction || this.assert; params.negate = this.negate; params.assertion = this; if (this.light) { throw new LightAssertionError(params); } else { throw new AssertionError(params); } }, /** * Shortcut for `Assertion#assert(false)`. * * @memberOf Assertion * @category assertion * @example * * var a = new should.Assertion(42); * * a.params = { * operator: 'to be magic number', * } * * a.fail(); * //throws AssertionError: expected 42 to be magic number */ fail: function() { return this.assert(false); }, assertZeroArguments: function(args) { if (args.length !== 0) { throw new TypeError("This assertion does not expect any arguments. You may need to check your code"); } } }; /** * Assertion used to delegate calls of Assertion methods inside of Promise. * It has almost all methods of Assertion.prototype * * @param {Promise} obj */ function PromisedAssertion(/* obj */) { Assertion.apply(this, arguments); } /** * Make PromisedAssertion to look like promise. Delegate resolve and reject to given promise. * * @private * @returns {Promise} */ PromisedAssertion.prototype.then = function(resolve, reject) { return this.obj.then(resolve, reject); }; /** * Way to extend Assertion function. It uses some logic * to define only positive assertions and itself rule with negative assertion. * * All actions happen in subcontext and this method take care about negation. * Potentially we can add some more modifiers that does not depends from state of assertion. * * @memberOf Assertion * @static * @param {String} name Name of assertion. It will be used for defining method or getter on Assertion.prototype * @param {Function} func Function that will be called on executing assertion * @example * * Assertion.add('asset', function() { * this.params = { operator: 'to be asset' } * * this.obj.should.have.property('id').which.is.a.Number() * this.obj.should.have.property('path') * }) */ Assertion.add = function(name, func) { Object.defineProperty(Assertion.prototype, name, { enumerable: true, configurable: true, value: function() { var context = new Assertion(this.obj, this, name); context.anyOne = this.anyOne; context.onlyThis = this.onlyThis; // hack context.light = true; try { func.apply(context, arguments); } catch (e) { // check for fail if (e instanceof AssertionError || e instanceof LightAssertionError) { // negative fail if (this.negate) { this.obj = context.obj; this.negate = false; return this; } if (context !== e.assertion) { context.params.previous = e; } // positive fail context.negate = false; // hack context.light = false; context.fail(); } // throw if it is another exception throw e; } // negative pass if (this.negate) { context.negate = true; // because .fail will set negate context.params.details = "false negative fail"; // hack context.light = false; context.fail(); } // positive pass if (!this.params.operator) { this.params = context.params; // shortcut } this.obj = context.obj; this.negate = false; return this; } }); Object.defineProperty(PromisedAssertion.prototype, name, { enumerable: true, configurable: true, value: function() { var args = arguments; this.obj = this.obj.then(function(a) { return a[name].apply(a, args); }); return this; } }); }; /** * Add chaining getter to Assertion like .a, .which etc * * @memberOf Assertion * @static * @param {string} name name of getter * @param {function} [onCall] optional function to call */ Assertion.addChain = function(name, onCall) { onCall = onCall || function() {}; Object.defineProperty(Assertion.prototype, name, { get: function() { onCall.call(this); return this; }, enumerable: true }); Object.defineProperty(PromisedAssertion.prototype, name, { enumerable: true, configurable: true, get: function() { this.obj = this.obj.then(function(a) { return a[name]; }); return this; } }); }; /** * Create alias for some `Assertion` property * * @memberOf Assertion * @static * @param {String} from Name of to map * @param {String} to Name of alias * @example * * Assertion.alias('true', 'True') */ Assertion.alias = function(from, to) { var desc = Object.getOwnPropertyDescriptor(Assertion.prototype, from); if (!desc) { throw new Error("Alias " + from + " -> " + to + " could not be created as " + from + " not defined"); } Object.defineProperty(Assertion.prototype, to, desc); var desc2 = Object.getOwnPropertyDescriptor(PromisedAssertion.prototype, from); if (desc2) { Object.defineProperty(PromisedAssertion.prototype, to, desc2); } }; /** * Negation modifier. Current assertion chain become negated. Each call invert negation on current assertion. * * @name not * @property * @memberOf Assertion * @category assertion */ Assertion.addChain("not", function() { this.negate = !this.negate; }); /** * Any modifier - it affect on execution of sequenced assertion to do not `check all`, but `check any of`. * * @name any * @property * @memberOf Assertion * @category assertion */ Assertion.addChain("any", function() { this.anyOne = true; }); /** * Only modifier - currently used with .keys to check if object contains only exactly this .keys * * @name only * @property * @memberOf Assertion * @category assertion */ Assertion.addChain("only", function() { this.onlyThis = true; }); // implement assert interface using already written peaces of should.js // http://wiki.commonjs.org/wiki/Unit_Testing/1.0 // // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! // // Originally from narwhal.js (http://narwhaljs.org) // Copyright (c) 2009 Thomas Robinson <280north.com> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the 'Software'), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // when used in node, this will actually load the util module we depend on // versus loading the builtin util module as happens otherwise // this is a bug in node module loading as far as I am concerned var pSlice = Array.prototype.slice; // 1. The assert module provides functions that throw // AssertionError's when particular conditions are not met. The // assert module must conform to the following interface. var assert = ok; // 3. All of the following functions must throw an AssertionError // when a corresponding condition is not met, with a message that // may be undefined if not provided. All assertion methods provide // both the actual and expected values to the assertion error for // display purposes. /** * Node.js standard [`assert.fail`](http://nodejs.org/api/assert.html#assert_assert_fail_actual_expected_message_operator). * @static * @memberOf should * @category assertion assert * @param {*} actual Actual object * @param {*} expected Expected object * @param {string} message Message for assertion * @param {string} operator Operator text */ function fail(actual, expected, message, operator, stackStartFunction) { var a = new Assertion(actual); a.params = { operator: operator, expected: expected, message: message, stackStartFunction: stackStartFunction || fail }; a.fail(); } // EXTENSION! allows for well behaved errors defined elsewhere. assert.fail = fail; // 4. Pure assertion tests whether a value is truthy, as determined // by !!guard. // assert.ok(guard, message_opt); // This statement is equivalent to assert.equal(true, !!guard, // message_opt);. To test strictly for the value true, use // assert.strictEqual(true, guard, message_opt);. /** * Node.js standard [`assert.ok`](http://nodejs.org/api/assert.html#assert_assert_value_message_assert_ok_value_message). * @static * @memberOf should * @category assertion assert * @param {*} value * @param {string} [message] */ function ok(value, message) { if (!value) { fail(value, true, message, "==", assert.ok); } } assert.ok = ok; // 5. The equality assertion tests shallow, coercive equality with // ==. // assert.equal(actual, expected, message_opt); /** * Node.js standard [`assert.equal`](http://nodejs.org/api/assert.html#assert_assert_equal_actual_expected_message). * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.equal = function equal(actual, expected, message) { if (actual != expected) { fail(actual, expected, message, "==", assert.equal); } }; // 6. The non-equality assertion tests for whether two objects are not equal // with != assert.notEqual(actual, expected, message_opt); /** * Node.js standard [`assert.notEqual`](http://nodejs.org/api/assert.html#assert_assert_notequal_actual_expected_message). * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.notEqual = function notEqual(actual, expected, message) { if (actual == expected) { fail(actual, expected, message, "!=", assert.notEqual); } }; // 7. The equivalence assertion tests a deep equality relation. // assert.deepEqual(actual, expected, message_opt); /** * Node.js standard [`assert.deepEqual`](http://nodejs.org/api/assert.html#assert_assert_deepequal_actual_expected_message). * But uses should.js .eql implementation instead of Node.js own deepEqual. * * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.deepEqual = function deepEqual(actual, expected, message) { if (eql(actual, expected).length !== 0) { fail(actual, expected, message, "deepEqual", assert.deepEqual); } }; // 8. The non-equivalence assertion tests for any deep inequality. // assert.notDeepEqual(actual, expected, message_opt); /** * Node.js standard [`assert.notDeepEqual`](http://nodejs.org/api/assert.html#assert_assert_notdeepequal_actual_expected_message). * But uses should.js .eql implementation instead of Node.js own deepEqual. * * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.notDeepEqual = function notDeepEqual(actual, expected, message) { if (eql(actual, expected).result) { fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual); } }; // 9. The strict equality assertion tests strict equality, as determined by ===. // assert.strictEqual(actual, expected, message_opt); /** * Node.js standard [`assert.strictEqual`](http://nodejs.org/api/assert.html#assert_assert_strictequal_actual_expected_message). * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.strictEqual = function strictEqual(actual, expected, message) { if (actual !== expected) { fail(actual, expected, message, "===", assert.strictEqual); } }; // 10. The strict non-equality assertion tests for strict inequality, as // determined by !==. assert.notStrictEqual(actual, expected, message_opt); /** * Node.js standard [`assert.notStrictEqual`](http://nodejs.org/api/assert.html#assert_assert_notstrictequal_actual_expected_message). * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.notStrictEqual = function notStrictEqual(actual, expected, message) { if (actual === expected) { fail(actual, expected, message, "!==", assert.notStrictEqual); } }; function expectedException(actual, expected) { if (!actual || !expected) { return false; } if (Object.prototype.toString.call(expected) == "[object RegExp]") { return expected.test(actual); } else if (actual instanceof expected) { return true; } else if (expected.call({}, actual) === true) { return true; } return false; } function _throws(shouldThrow, block, expected, message) { var actual; if (typeof expected == "string") { message = expected; expected = null; } try { block(); } catch (e) { actual = e; } message = (expected && expected.name ? " (" + expected.name + ")" : ".") + (message ? " " + message : "."); if (shouldThrow && !actual) { fail(actual, expected, "Missing expected exception" + message); } if (!shouldThrow && expectedException(actual, expected)) { fail(actual, expected, "Got unwanted exception" + message); } if ( (shouldThrow && actual && expected && !expectedException(actual, expected)) || (!shouldThrow && actual) ) { throw actual; } } // 11. Expected to throw an error: // assert.throws(block, Error_opt, message_opt); /** * Node.js standard [`assert.throws`](http://nodejs.org/api/assert.html#assert_assert_throws_block_error_message). * @static * @memberOf should * @category assertion assert * @param {Function} block * @param {Function} [error] * @param {String} [message] */ assert.throws = function(/*block, error, message*/) { _throws.apply(this, [true].concat(pSlice.call(arguments))); }; // EXTENSION! This is annoying to write outside this module. /** * Node.js standard [`assert.doesNotThrow`](http://nodejs.org/api/assert.html#assert_assert_doesnotthrow_block_message). * @static * @memberOf should * @category assertion assert * @param {Function} block * @param {String} [message] */ assert.doesNotThrow = function(/*block, message*/) { _throws.apply(this, [false].concat(pSlice.call(arguments))); }; /** * Node.js standard [`assert.ifError`](http://nodejs.org/api/assert.html#assert_assert_iferror_value). * @static * @memberOf should * @category assertion assert * @param {Error} err */ assert.ifError = function(err) { if (err) { throw err; } }; /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ function assertExtensions(should) { var i = should.format; /* * Expose assert to should * * This allows you to do things like below * without require()ing the assert module. * * should.equal(foo.bar, undefined); * */ merge(should, assert); /** * Assert _obj_ exists, with optional message. * * @static * @memberOf should * @category assertion assert * @alias should.exists * @param {*} obj * @param {String} [msg] * @example * * should.exist(1); * should.exist(new Date()); */ should.exist = should.exists = function(obj, msg) { if (null == obj) { throw new AssertionError({ message: msg || "expected " + i(obj) + " to exist", stackStartFunction: should.exist }); } }; should.not = {}; /** * Asserts _obj_ does not exist, with optional message. * * @name not.exist * @static * @memberOf should * @category assertion assert * @alias should.not.exists * @param {*} obj * @param {String} [msg] * @example * * should.not.exist(null); * should.not.exist(void 0); */ should.not.exist = should.not.exists = function(obj, msg) { if (null != obj) { throw new AssertionError({ message: msg || "expected " + i(obj) + " to not exist", stackStartFunction: should.not.exist }); } }; } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ function chainAssertions(should, Assertion) { /** * Simple chaining to improve readability. Does nothing. * * @memberOf Assertion * @name be * @property {should.Assertion} be * @alias Assertion#an * @alias Assertion#of * @alias Assertion#a * @alias Assertion#and * @alias Assertion#been * @alias Assertion#have * @alias Assertion#has * @alias Assertion#with * @alias Assertion#is * @alias Assertion#which * @alias Assertion#the * @alias Assertion#it * @category assertion chaining */ [ "an", "of", "a", "and", "be", "been", "has", "have", "with", "is", "which", "the", "it" ].forEach(function(name) { Assertion.addChain(name); }); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ function booleanAssertions(should, Assertion) { /** * Assert given object is exactly `true`. * * @name true * @memberOf Assertion * @category assertion bool * @alias Assertion#True * @param {string} [message] Optional message * @example * * (true).should.be.true(); * false.should.not.be.true(); * * ({ a: 10}).should.not.be.true(); */ Assertion.add("true", function(message) { this.is.exactly(true, message); }); Assertion.alias("true", "True"); /** * Assert given object is exactly `false`. * * @name false * @memberOf Assertion * @category assertion bool * @alias Assertion#False * @param {string} [message] Optional message * @example * * (true).should.not.be.false(); * false.should.be.false(); */ Assertion.add("false", function(message) { this.is.exactly(false, message); }); Assertion.alias("false", "False"); /** * Assert given object is truthy according javascript type conversions. * * @name ok * @memberOf Assertion * @category assertion bool * @example * * (true).should.be.ok(); * ''.should.not.be.ok(); * should(null).not.be.ok(); * should(void 0).not.be.ok(); * * (10).should.be.ok(); * (0).should.not.be.ok(); */ Assertion.add("ok", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be truthy" }; this.assert(this.obj); }); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ function numberAssertions(should, Assertion) { /** * Assert given object is NaN * @name NaN * @memberOf Assertion * @category assertion numbers * @example * * (10).should.not.be.NaN(); * NaN.should.be.NaN(); */ Assertion.add("NaN", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be NaN" }; this.assert(this.obj !== this.obj); }); /** * Assert given object is not finite (positive or negative) * * @name Infinity * @memberOf Assertion * @category assertion numbers * @example * * (10).should.not.be.Infinity(); * NaN.should.not.be.Infinity(); */ Assertion.add("Infinity", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be Infinity" }; this.is.a .Number() .and.not.a.NaN() .and.assert(!isFinite(this.obj)); }); /** * Assert given number between `start` and `finish` or equal one of them. * * @name within * @memberOf Assertion * @category assertion numbers * @param {number} start Start number * @param {number} finish Finish number * @param {string} [description] Optional message * @example * * (10).should.be.within(0, 20); */ Assertion.add("within", function(start, finish, description) { this.params = { operator: "to be within " + start + ".." + finish, message: description }; this.assert(this.obj >= start && this.obj <= finish); }); /** * Assert given number near some other `value` within `delta` * * @name approximately * @memberOf Assertion * @category assertion numbers * @param {number} value Center number * @param {number} delta Radius * @param {string} [description] Optional message * @example * * (9.99).should.be.approximately(10, 0.1); */ Assertion.add("approximately", function(value, delta, description) { this.params = { operator: "to be approximately " + value + " ±" + delta, message: description }; this.assert(Math.abs(this.obj - value) <= delta); }); /** * Assert given number above `n`. * * @name above * @alias Assertion#greaterThan * @memberOf Assertion * @category assertion numbers * @param {number} n Margin number * @param {string} [description] Optional message * @example * * (10).should.be.above(0); */ Assertion.add("above", function(n, description) { this.params = { operator: "to be above " + n, message: description }; this.assert(this.obj > n); }); /** * Assert given number below `n`. * * @name below * @alias Assertion#lessThan * @memberOf Assertion * @category assertion numbers * @param {number} n Margin number * @param {string} [description] Optional message * @example * * (0).should.be.below(10); */ Assertion.add("below", function(n, description) { this.params = { operator: "to be below " + n, message: description }; this.assert(this.obj < n); }); Assertion.alias("above", "greaterThan"); Assertion.alias("below", "lessThan"); /** * Assert given number above `n`. * * @name aboveOrEqual * @alias Assertion#greaterThanOrEqual * @memberOf Assertion * @category assertion numbers * @param {number} n Margin number * @param {string} [description] Optional message * @example * * (10).should.be.aboveOrEqual(0); * (10).should.be.aboveOrEqual(10); */ Assertion.add("aboveOrEqual", function(n, description) { this.params = { operator: "to be above or equal " + n, message: description }; this.assert(this.obj >= n); }); /** * Assert given number below `n`. * * @name belowOrEqual * @alias Assertion#lessThanOrEqual * @memberOf Assertion * @category assertion numbers * @param {number} n Margin number * @param {string} [description] Optional message * @example * * (0).should.be.belowOrEqual(10); * (0).should.be.belowOrEqual(0); */ Assertion.add("belowOrEqual", function(n, description) { this.params = { operator: "to be below or equal " + n, message: description }; this.assert(this.obj <= n); }); Assertion.alias("aboveOrEqual", "greaterThanOrEqual"); Assertion.alias("belowOrEqual", "lessThanOrEqual"); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ function typeAssertions(should, Assertion) { /** * Assert given object is number * @name Number * @memberOf Assertion * @category assertion types */ Assertion.add("Number", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a number" }; this.have.type("number"); }); /** * Assert given object is arguments * @name arguments * @alias Assertion#Arguments * @memberOf Assertion * @category assertion types */ Assertion.add("arguments", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be arguments" }; this.have.class("Arguments"); }); Assertion.alias("arguments", "Arguments"); /** * Assert given object has some type using `typeof` * @name type * @memberOf Assertion * @param {string} type Type name * @param {string} [description] Optional message * @category assertion types */ Assertion.add("type", function(type, description) { this.params = { operator: "to have type " + type, message: description }; should(typeof this.obj).be.exactly(type); }); /** * Assert given object is instance of `constructor` * @name instanceof * @alias Assertion#instanceOf * @memberOf Assertion * @param {Function} constructor Constructor function * @param {string} [description] Optional message * @category assertion types */ Assertion.add("instanceof", function(constructor, description) { this.params = { operator: "to be an instance of " + functionName(constructor), message: description }; this.assert(Object(this.obj) instanceof constructor); }); Assertion.alias("instanceof", "instanceOf"); /** * Assert given object is function * @name Function * @memberOf Assertion * @category assertion types */ Assertion.add("Function", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a function" }; this.have.type("function"); }); /** * Assert given object is object * @name Object * @memberOf Assertion * @category assertion types */ Assertion.add("Object", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be an object" }; this.is.not.null().and.have.type("object"); }); /** * Assert given object is string * @name String * @memberOf Assertion * @category assertion types */ Assertion.add("String", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a string" }; this.have.type("string"); }); /** * Assert given object is array * @name Array * @memberOf Assertion * @category assertion types */ Assertion.add("Array", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be an array" }; this.have.class("Array"); }); /** * Assert given object is boolean * @name Boolean * @memberOf Assertion * @category assertion types */ Assertion.add("Boolean", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a boolean" }; this.have.type("boolean"); }); /** * Assert given object is error * @name Error * @memberOf Assertion * @category assertion types */ Assertion.add("Error", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be an error" }; this.have.instanceOf(Error); }); /** * Assert given object is a date * @name Date * @memberOf Assertion * @category assertion types */ Assertion.add("Date", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a date" }; this.have.instanceOf(Date); }); /** * Assert given object is null * @name null * @alias Assertion#Null * @memberOf Assertion * @category assertion types */ Assertion.add("null", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be null" }; this.assert(this.obj === null); }); Assertion.alias("null", "Null"); /** * Assert given object has some internal [[Class]], via Object.prototype.toString call * @name class * @alias Assertion#Class * @memberOf Assertion * @category assertion types */ Assertion.add("class", function(cls) { this.params = { operator: "to have [[Class]] " + cls }; this.assert(Object.prototype.toString.call(this.obj) === "[object " + cls + "]"); }); Assertion.alias("class", "Class"); /** * Assert given object is undefined * @name undefined * @alias Assertion#Undefined * @memberOf Assertion * @category assertion types */ Assertion.add("undefined", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be undefined" }; this.assert(this.obj === void 0); }); Assertion.alias("undefined", "Undefined"); /** * Assert given object supports es6 iterable protocol (just check * that object has property Symbol.iterator, which is a function) * @name iterable * @memberOf Assertion * @category assertion es6 */ Assertion.add("iterable", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be iterable" }; should(this.obj) .have.property(Symbol.iterator) .which.is.a.Function(); }); /** * Assert given object supports es6 iterator protocol (just check * that object has property next, which is a function) * @name iterator * @memberOf Assertion * @category assertion es6 */ Assertion.add("iterator", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be iterator" }; should(this.obj) .have.property("next") .which.is.a.Function(); }); /** * Assert given object is a generator object * @name generator * @memberOf Assertion * @category assertion es6 */ Assertion.add("generator", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be generator" }; should(this.obj).be.iterable.and.iterator.and.it.is.equal(this.obj[Symbol.iterator]()); }); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ function formatEqlResult(r, a, b) { return ((r.path.length > 0 ? "at " + r.path.map(formatProp).join(" -> ") : "") + (r.a === a ? "" : ", A has " + format(r.a)) + (r.b === b ? "" : " and B has " + format(r.b)) + (r.showReason ? " because " + r.reason : "")).trim(); } function equalityAssertions(should, Assertion) { /** * Deep object equality comparison. For full spec see [`should-equal tests`](https://github.com/shouldjs/equal/blob/master/test.js). * * @name eql * @memberOf Assertion * @category assertion equality * @alias Assertion#eqls * @alias Assertion#deepEqual * @param {*} val Expected value * @param {string} [description] Optional message * @example * * (10).should.be.eql(10); * ('10').should.not.be.eql(10); * (-0).should.not.be.eql(+0); * * NaN.should.be.eql(NaN); * * ({ a: 10}).should.be.eql({ a: 10 }); * [ 'a' ].should.not.be.eql({ '0': 'a' }); */ Assertion.add("eql", function(val, description) { this.params = { operator: "to equal", expected: val, message: description }; var obj = this.obj; var fails = eql(this.obj, val, should.config); this.params.details = fails .map(function(fail) { return formatEqlResult(fail, obj, val); }) .join(", "); this.params.showDiff = eql(getType(obj), getType(val)).length === 0; this.assert(fails.length === 0); }); /** * Exact comparison using ===. * * @name equal * @memberOf Assertion * @category assertion equality * @alias Assertion#equals * @alias Assertion#exactly * @param {*} val Expected value * @param {string} [description] Optional message * @example * * 10.should.be.equal(10); * 'a'.should.be.exactly('a'); * * should(null).be.exactly(null); */ Assertion.add("equal", function(val, description) { this.params = { operator: "to be", expected: val, message: description }; this.params.showDiff = eql(getType(this.obj), getType(val)).length === 0; this.assert(val === this.obj); }); Assertion.alias("equal", "equals"); Assertion.alias("equal", "exactly"); Assertion.alias("eql", "eqls"); Assertion.alias("eql", "deepEqual"); function addOneOf(name, message, method) { Assertion.add(name, function(vals) { if (arguments.length !== 1) { vals = Array.prototype.slice.call(arguments); } else { should(vals).be.Array(); } this.params = { operator: message, expected: vals }; var obj = this.obj; var found = false; forEach(vals, function(val) { try { should(val)[method](obj); found = true; return false; } catch (e) { if (e instanceof should.AssertionError) { return; //do nothing } throw e; } }); this.assert(found); }); } /** * Exact comparison using === to be one of supplied objects. * * @name equalOneOf * @memberOf Assertion * @category assertion equality * @param {Array|*} vals Expected values * @example * * 'ab'.should.be.equalOneOf('a', 10, 'ab'); * 'ab'.should.be.equalOneOf(['a', 10, 'ab']); */ addOneOf("equalOneOf", "to be equals one of", "equal"); /** * Exact comparison using .eql to be one of supplied objects. * * @name oneOf * @memberOf Assertion * @category assertion equality * @param {Array|*} vals Expected values * @example * * ({a: 10}).should.be.oneOf('a', 10, 'ab', {a: 10}); * ({a: 10}).should.be.oneOf(['a', 10, 'ab', {a: 10}]); */ addOneOf("oneOf", "to be one of", "eql"); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ function promiseAssertions(should, Assertion$$1) { /** * Assert given object is a Promise * * @name Promise * @memberOf Assertion * @category assertion promises * @example * * promise.should.be.Promise() * (new Promise(function(resolve, reject) { resolve(10); })).should.be.a.Promise() * (10).should.not.be.a.Promise() */ Assertion$$1.add("Promise", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be promise" }; var obj = this.obj; should(obj) .have.property("then") .which.is.a.Function(); }); /** * Assert given promise will be fulfilled. Result of assertion is still .thenable and should be handled accordingly. * * @name fulfilled * @memberOf Assertion * @alias Assertion#resolved * @returns {Promise} * @category assertion promises * @example * * // don't forget to handle async nature * (new Promise(function(resolve, reject) { resolve(10); })).should.be.fulfilled(); * * // test example with mocha it is possible to return promise * it('is async', () => { * return new Promise(resolve => resolve(10)) * .should.be.fulfilled(); * }); */ Assertion$$1.prototype.fulfilled = function Assertion$fulfilled() { this.assertZeroArguments(arguments); this.params = { operator: "to be fulfilled" }; should(this.obj).be.a.Promise(); var that = this; return this.obj.then( function next$onResolve(value) { if (that.negate) { that.fail(); } return value; }, function next$onReject(err) { if (!that.negate) { that.params.operator += ", but it was rejected with " + should.format(err); that.fail(); } return err; } ); }; Assertion$$1.prototype.resolved = Assertion$$1.prototype.fulfilled; /** * Assert given promise will be rejected. Result of assertion is still .thenable and should be handled accordingly. * * @name rejected * @memberOf Assertion * @category assertion promises * @returns {Promise} * @example * * // don't forget to handle async nature * (new Promise(function(resolve, reject) { resolve(10); })) * .should.not.be.rejected(); * * // test example with mocha it is possible to return promise * it('is async', () => { * return new Promise((resolve, reject) => reject(new Error('boom'))) * .should.be.rejected(); * }); */ Assertion$$1.prototype.rejected = function() { this.assertZeroArguments(arguments); this.params = { operator: "to be rejected" }; should(this.obj).be.a.Promise(); var that = this; return this.obj.then( function(value) { if (!that.negate) { that.params.operator += ", but it was fulfilled"; if (arguments.length != 0) { that.params.operator += " with " + should.format(value); } that.fail(); } return value; }, function next$onError(err) { if (that.negate) { that.fail(); } return err; } ); }; /** * Assert given promise will be fulfilled with some expected value (value compared using .eql). * Result of assertion is still .thenable and should be handled accordingly. * * @name fulfilledWith * @memberOf Assertion * @alias Assertion#resolvedWith * @category assertion promises * @returns {Promise} * @example * * // don't forget to handle async nature * (new Promise(function(resolve, reject) { resolve(10); })) * .should.be.fulfilledWith(10); * * // test example with mocha it is possible to return promise * it('is async', () => { * return new Promise((resolve, reject) => resolve(10)) * .should.be.fulfilledWith(10); * }); */ Assertion$$1.prototype.fulfilledWith = function(expectedValue) { this.params = { operator: "to be fulfilled with " + should.format(expectedValue) }; should(this.obj).be.a.Promise(); var that = this; return this.obj.then( function(value) { if (that.negate) { that.fail(); } should(value).eql(expectedValue); return value; }, function next$onError(err) { if (!that.negate) { that.params.operator += ", but it was rejected with " + should.format(err); that.fail(); } return err; } ); }; Assertion$$1.prototype.resolvedWith = Assertion$$1.prototype.fulfilledWith; /** * Assert given promise will be rejected with some sort of error. Arguments is the same for Assertion#throw. * Result of assertion is still .thenable and should be handled accordingly. * * @name rejectedWith * @memberOf Assertion * @category assertion promises * @returns {Promise} * @example * * function failedPromise() { * return new Promise(function(resolve, reject) { * reject(new Error('boom')) * }) * } * failedPromise().should.be.rejectedWith(Error); * failedPromise().should.be.rejectedWith('boom'); * failedPromise().should.be.rejectedWith(/boom/); * failedPromise().should.be.rejectedWith(Error, { message: 'boom' }); * failedPromise().should.be.rejectedWith({ message: 'boom' }); * * // test example with mocha it is possible to return promise * it('is async', () => { * return failedPromise().should.be.rejectedWith({ message: 'boom' }); * }); */ Assertion$$1.prototype.rejectedWith = function(message, properties) { this.params = { operator: "to be rejected" }; should(this.obj).be.a.Promise(); var that = this; return this.obj.then( function(value) { if (!that.negate) { that.fail(); } return value; }, function next$onError(err) { if (that.negate) { that.fail(); } var errorMatched = true; var errorInfo = ""; if ("string" === typeof message) { errorMatched = message === err.message; } else if (message instanceof RegExp) { errorMatched = message.test(err.message); } else if ("function" === typeof message) { errorMatched = err instanceof message; } else if (message !== null && typeof message === "object") { try { should(err).match(message); } catch (e) { if (e instanceof should.AssertionError) { errorInfo = ": " + e.message; errorMatched = false; } else { throw e; } } } if (!errorMatched) { if (typeof message === "string" || message instanceof RegExp) { errorInfo = " with a message matching " + should.format(message) + ", but got '" + err.message + "'"; } else if ("function" === typeof message) { errorInfo = " of type " + functionName(message) + ", but got " + functionName(err.constructor); } } else if ("function" === typeof message && properties) { try { should(err).match(properties); } catch (e) { if (e instanceof should.AssertionError) { errorInfo = ": " + e.message; errorMatched = false; } else { throw e; } } } that.params.operator += errorInfo; that.assert(errorMatched); return err; } ); }; /** * Assert given object is promise and wrap it in PromisedAssertion, which has all properties of Assertion. * That means you can chain as with usual Assertion. * Result of assertion is still .thenable and should be handled accordingly. * * @name finally * @memberOf Assertion * @alias Assertion#eventually * @category assertion promises * @returns {PromisedAssertion} Like Assertion, but .then this.obj in Assertion * @example * * (new Promise(function(resolve, reject) { resolve(10); })) * .should.be.eventually.equal(10); * * // test example with mocha it is possible to return promise * it('is async', () => { * return new Promise(resolve => resolve(10)) * .should.be.finally.equal(10); * }); */ Object.defineProperty(Assertion$$1.prototype, "finally", { get: function() { should(this.obj).be.a.Promise(); var that = this; return new PromisedAssertion( this.obj.then(function(obj) { var a = should(obj); a.negate = that.negate; a.anyOne = that.anyOne; return a; }) ); } }); Assertion$$1.alias("finally", "eventually"); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca> * Copyright(c) 2013-2017 Denis Bardadym <bardadymchik@gmail.com> * MIT Licensed */ function stringAssertions(should, Assertion) { /** * Assert given string starts with prefix * @name startWith * @memberOf Assertion * @category assertion strings * @param {string} str Prefix * @param {string} [description] Optional message * @example * * 'abc'.should.startWith('a'); */ Assertion.add("startWith", function(str, description) { this.params = { operator: "to start with " + should.format(str), message: des