should
Version:
test framework agnostic BDD-style assertions
1,867 lines (1,664 loc) • 83.6 kB
JavaScript
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