referee
A collection of assertions to be used with a unit testing framework. referee works well with any CommonJS compliant testing framework out of the box, and can easily be configured to work with most any testing framework. See also expectations if you like the alternative API
(expect(thing).toBe*
).
referee contains lots of assertions. We strongly believe that high-level assertions are essential in the interest of producing clear and intent-revealing tests, and they also give you to-the-point failure messages.
Install
npm install @sinonjs/referee --save-dev
Sinon.JS integration
You can extend referee with assertions that integrates with Sinon.JS
See referee-sinon
Assertions and refutations
Unlike most assertion libraries, referee does not have assert.notXyz
assertions to refute some fact. Instead, it has refutations, heavily inspired by Ruby's minitest:
var assert = referee.assert;
var refute = referee.refute;
assert.equals(42, 42);
refute.equals(42, 43);
Refutations help express "assert not ..." style verification in a much clearer way. It also brings with it a nice consistency in that any assert.xyz
always has a corresponding refute.xyz
that does the opposite check.
assert()
assert(actual[, message]);
Fails if actual
is falsy (0
, ""
, null
, undefined
, NaN
). Fails with either the provided message or "Expected null to be truthy". This behavior differs from all other assertions, which prepend the optional message argument.
assert({ not: "Falsy" }, "This will pass");
assert(null, "This will fail"); // Fails with custom message
assert(null); // Fails
assert(34); // Passes
refute()
refute(actual[, message])
Fails if actual is truthy. Fails with either the provided message or "Expected null to be falsy". This behavior differs from all other refutations, which prepend the optional message argument.
refute({ not: "Falsy" }, "This will fail"); // Fails with custom message
refute(null, "This will pass");
refute(null); // Passes
refute(34); // Fails
Predefined Assertions
The following assertions can be used with assert
and refute
. They
are described for assert
, but the corresponding failure messages for
refute
are also mentioned. For refute
the behaviour is exactly
opposed.
All assertions support an optional message
argument, which is
prepended to the failure message.
Overview
Any
String
Number
Function
Object
Array and array like
DOM element
Promise
Types and values
These assertions are for checking for built-in types and values.
isUndefined()
isNull()
isArray()
isArrayBuffer()
isArrayLike()
isBoolean()
isDataView()
isDate()
isError()
isEvalError()
isFalse()
isFloat32Array()
isFloat64Array()
isFunction()
isInfinity()
isIntlCollator()
isIntlDateTimeFormat()
isIntlNumberFormat()
isMap()
isNaN()
isNegativeInfinity()
isNumber()
isObject()
isPromise()
isRangeError()
isReferenceError()
isRegExp()
isSet()
isString()
isSymbol()
isSyntaxError()
isTrue()
isTypeError()
isUint16Array()
isUint32Array()
isUint8Array()
isUint8Array()
isUint8clampedArray()
isURIError()
isWeakMap()
isWeakSet()
same()
assert.same(actual, expected[, message])
Fails if actual
is not the same object (===
) as expected
. To compare similar objects, such as { name: "Chris", id: 42 } and { id: 42, name: "Chris" } (not the same instance), see equals()
.
var obj = { id: 42, name: "Chris" };
assert.same(obj, obj); // Passes
assert.same(obj, { id: 42, name: "Chris" }); // Fails
Messages
assert.same.message = "${actual} expected to be the same object as ${expected}";
refute.same.message =
"${actual} expected not to be the same object as ${expected}";
equals()
assert.equals(actual, expected[, message])
Compares actual
to expected
property by property. If the property count does not match, or if any of actual
‘s properties do not match the corresponding property in expected
, the assertion fails. Object properties are verified recursively.
If actual
is null
or undefined
, an exact match is required. Date objects are compared by their getTime
method. Regular expressions are compared by their string representations. Primitives are compared using ==
, i.e., with coercion.
equals
passes when comparing an arguments object to an array if the both contain the same elements.
Objects or arrays may contain the result of calling match
to compare a property using a built-in or custom matcher.
assert.equals({ name: "Professor Chaos" }, { name: "Professor Chaos" }); // Passes
assert.equals({ name: "Professor Chaos" }, { name: match.string }); // Passes
assert.equals({ name: "Professor Chaos" }, { name: "Dr Evil" }); // Fails
assert.equals({ name: "Professor Chaos" }, { name: match.number }); // Fails
Messages
assert.equals.message = "${actual} expected to be equal to ${expected}";
refute.equals.message = "${actual} expected not to be equal to ${expected}";
greater()
assert.greater(actual, expected[, message])
Fails if actual
is equal to or less than expected
.
assert.greater(2, 1); // Passes
assert.greater(1, 1); // Fails
assert.greater(1, 2); // Fails
Messages
assert.greater.message = "Expected ${actual} to be greater than ${expected}";
refute.greater.message =
"Expected ${actual} to be less than or equal to ${expected}";
less()
assert.less(actual, expected[, message])
Fails if actual
is equal to or greater than expected
.
assert.less(1, 2); // Passes
assert.less(1, 1); // Fails
assert.less(2, 1); // Fails
Messages
assert.less.message = "Expected ${actual} to be less than ${expected}";
refute.less.message =
"Expected ${actual} to be greater than or equal to ${expected}";
isUndefined()
assert.isUndefined(object[, message])
Fails if object
is not undefined
.
assert.isUndefined(undefined); // Passes
assert.isUndefined({}); // Fails
refute.isUndefined({}); // Passes
refute.isUndefined(undefined); // Fails
Messages
assert.isUndefined.message = "Expected ${actual} to be undefined";
refute.isUndefined.message = "Expected not to be undefined";
isNull()
assert.isNull(object[, message])
Fails if object
is not null
.
assert.isNull(null); // Passes
assert.isNull({}); // Fails
refute.isNull({}); // Passes
refute.isNull(null); // Fails
Messages
assert.isNull.message = "Expected ${actual} to be null";
refute.isNull.message = "Expected not to be null";
match()
assert.match(actual, matcher[, message])
Fails if matcher
is not a partial match for actual
. Accepts a wide range of input combinations. Note that assert.match
is not symmetric - in some cases assert.match(a, b)
may pass while assert.match(b, a)
fails.
String matcher
In its simplest form, assert.match
performs a case insensitive substring match. When the matcher is a string, the actual
object is converted to a string, and the assertion passes if actual
is a case-insensitive substring of expected as a string.
assert.match("Give me something", "Give"); // Passes
assert.match("Give me something", "sumptn"); // Fails
assert.match(
{
toString: function () {
return "yeah";
},
},
"Yeah!",
); // Passes
The last example is not symmetric. When the matcher is a string, the actual value is coerced to a string - in this case using toString
. Changing the order of the arguments would cause the matcher to be an object, in which case different rules apply (see below).
Boolean matcher
Performs a strict (i.e. ===
) match with the object. So, only true
matches true
, and only false
matches false
.
Regular expression matcher
When the matcher is a regular expression, the assertion will pass if expected.test(actual)
is true
. assert.match
is written in a generic way, so any object with a test
method will be used as a matcher this way.
assert.match("Give me something", /^[a-z\s]$/i); // Passes
assert.match("Give me something", /[0-9]/); // Fails
assert.match(
{
toString: function () {
return "yeah!";
},
},
/yeah/,
); // Passes
assert.match(234, /[a-z]/); // Fails
Number matcher
When the matcher is a number, the assertion will pass if matcher == actual
.
assert.match("123", 123); // Passes
assert.match("Give me something", 425); // Fails
assert.match(
{
toString: function () {
return "42";
},
},
42,
); // Passes
assert.match(234, 1234); // Fails
Function matcher
When the matcher is a function, it is called with actual
as its only argument. The assertion will pass if the function returns true
. A strict match is performed against the return value, so a boolean true
is required, truthy is not enough.
// Passes
assert.match("123", function (exp) {
return exp == "123";
});
// Fails
assert.match("Give me something", function () {
return "ok";
});
// Passes
assert.match(
{
toString: function () {
return "42";
},
},
function () {
return true;
},
);
// Fails
assert.match(234, function () {});
Object matcher
As mentioned above, if an object matcher defines a test method the assertion will pass if matcher.test(actual)
returns truthy. If the object does not have a test
method, a recursive match is performed. If all properties of matcher
matches corresponding properties in actual
, the assertion passes. Note that the object matcher does not care if the number of properties in the two objects are the same - only if all properties in the matcher recursively “matches” ones in the actual object.
// Passes
assert.match("123", {
test: function (arg) {
return arg == 123;
},
});
// Fails
assert.match({}, { prop: 42 });
// Passes
assert.match(
{
name: "Chris",
profession: "Programmer",
},
{
name: "Chris",
},
);
// Fails
assert.match(234, {
name: "Chris",
});
DOM elements
assert.match
can be very helpful when asserting on DOM elements, because it allows you to compare several properties with one assertion:
var el = document.getElementById("myEl");
assert.match(el, {
tagName: "h2",
className: "item",
innerHTML: "Howdy",
});
isObject()
assert.isObject(object[, message])
Fails if object
is not an object or if it is null
.
assert.isObject({}); // Passes
assert.isObject(42); // Fails
assert.isObject([1, 2, 3]); // Passes
assert.isObject(function () {}); // Fails
Messages
assert.isObject.message =
"${actual} (${actualType}) expected to be object and not null";
refute.isObject.message = "${actual} expected to be null or not an object";
isFunction()
assert.isFunction(actual[, message])
Fails if actual
is not a function.
assert.isFunction({}); // Fails
assert.isFunction(42); // Fails
assert.isFunction(function () {}); // Passes
Messages
assert.isFunction.message = "${actual} (${actualType}) expected to be function";
refute.isFunction.message = "${actual} expected not to be function";
isTrue()
assert.isTrue(actual[, message])
Fails if actual
is not true
.
assert.isTrue("2" == 2); // Passes
assert.isTrue("2" === 2); // Fails
Messages
assert.isTrue.message = "Expected ${actual} to be true";
refute.isTrue.message = "Expected ${actual} to not be true";
isFalse()
assert.isFalse(actual[, message])
Fails if actual
is not false
.
assert.isFalse("2" === 2); // Passes
assert.isFalse("2" == 2); // Fails
Messages
assert.isFalse.message = "Expected ${actual} to be false";
refute.isFalse.message = "Expected ${actual} to not be false";
isString()
assert.isString(actual[, message])
Fails if the type of actual is not "string".
assert.isString("2"); // Passes
assert.isString(2); // Fails
Messages
assert.isString.message = "Expected ${actual} (${actualType}) to be string";
refute.isString.message = "Expected ${actual} not to be string";
isBoolean()
assert.isBoolean(actual[, message])
Fails if the type of actual
is not "boolean".
assert.isBoolean(true); // Passes
assert.isBoolean(2 < 2); // Passes
assert.isBoolean("true"); // Fails
Messages
assert.isBoolean.message = "Expected ${actual} (${actualType}) to be boolean";
refute.isBoolean.message = "Expected ${actual} not to be boolean";
isNumber()
assert.isNumber(actual[, message])
Fails if the type of actual
is not "number" or is NaN
.
assert.isNumber(12); // Passes
assert.isNumber("12"); // Fails
assert.isNumber(NaN); // Fails
Messages
assert.isNumber.message =
"Expected ${actual} (${actualType}) to be a non-NaN number";
refute.isNumber.message = "Expected ${actual} to be NaN or a non-number value";
isNaN()
assert.isNaN(actual[, message])
Fails if actual
is not NaN
. Does not perform coercion in contrast to the standard javascript function isNaN
.
assert.isNaN(NaN); // Passes
assert.isNaN("abc" / "def"); // Passes
assert.isNaN(12); // Fails
assert.isNaN({}); // Fails, would pass for standard javascript function isNaN
Messages
assert.isNaN.message = "Expected ${actual} to be NaN";
refute.isNaN.message = "Expected not to be NaN";
isNegativeInfinity()
assert.isNegativeInfinity(actual[, message])
Fails if actual
is not -Infinity
.
assert.isNegativeInfinity(-Infinity); // Passes
assert.isNegativeInfinity(42); // Fails
isArray()
assert.isArray(actual[, message])
Fails if the object type of actual
is not Array
.
assert.isArray([1, 2, 3]); // Passes
assert.isArray({}); // Fails
Messages
assert.isArray.message = "Expected ${actual} to be array";
refute.isArray.message = "Expected ${actual} not to be array";
isArrayBuffer()
assert.isArrayBuffer(actual[, message])
Fails if the object type of actual
is not ArrayBuffer
.
assert.isArrayBuffer(new ArrayBuffer(8)); // Passes
assert.isArrayBuffer({}); // Fails
Messages
assert.isArrayBuffer.message = "Expected ${actual} to be an ArrayBuffer";
refute.isArrayBuffer.message = "Expected ${actual} not to be an ArrayBuffer";
isArrayLike()
assert.isArrayLike(actual[, message])
Fails if none of the following conditions are fulfilled:
- the object type of
actual
isArray
actual
is anarguments
objectactual
is an object providing a propertylength
of type "number" and aproperty
splice of type "function"
assert.isArrayLike([1, 2, 3]); // Passes
assert.isArrayLike(arguments); // Passes
assert.isArrayLike({ length: 0, splice: function () {} }); // Passes
assert.isArrayLike({}); // Fails
Messages
assert.isArrayLike.message = "Expected ${actual} to be array like";
refute.isArrayLike.message = "Expected ${actual} not to be array like";
isDataView()
assert.isDataView(actual[, message])
Fails if the object type of actual
is not DataView
.
assert.isDataView(new DataView(new ArrayBuffer(16)); // Passes
assert.isDataView({}); // Fails
Messages
assert.isDataView.message = "Expected ${actual} to be a DataView";
refute.isDataView.message = "Expected ${actual} not to be a DataView";
isDate()
assert.isDate(actual[, message])
Fails if actual
is not an instance of Date
.
assert.isDate(new Date()); // Passes
assert.isDate(12345678); // Fails
assert.isDate("apple pie"); // Fails
Messages
assert.isDate.message = "Expected ${actual} to be a Date";
refute.isDate.message = "Expected ${actual} not to be a Date";
isError()
assert.isError(actual[, message])
Fails if actual
is not an instance of Error
.
Passes for all built in error types and errors derived from a built in error type.
assert.isError(new Error("this is an error"); // Passes
assert.isError("this is not an error"); // Fails
Messages
assert.isError.message = "Expected ${actual} to be an Error";
refute.isError.message = "Expected ${actual} not to be an Error";
isEvalError()
assert.isEvalError(actual[, message])
Fails if actual
is not an instance of EvalError
.
assert.isEvalError(new EvalError("this is an eval error")); // Passes
assert.isEvalError(new Error("this is not an eval error")); // Fails
Messages
assert.isEvalError.message = "Expected ${actual} to be an EvalError";
refute.isEvalError.message = "Expected ${actual} not to be an EvalError";
isFloat32Array()
assert.isFloat32Array(actual[, message])
Fails if actual
is not an instance of Float32Array
.
assert.isFloat32Array(new Float32Array(2)); // Passes
assert.isFloat32Array(new Float64Array(2)); // Fails
Messages
assert.isFloat32Array.message = "Expected ${actual} to be a Float32Array";
refute.isFloat32Array.message = "Expected ${actual} not to be n Float32Array";
isFloat64Array()
assert.isFloat64Array(actual[, message])
Fails if actual
is not an instance of Float64Array
.
assert.isFloat64Array(new Float64Array(2)); // Passes
assert.isFloat64Array(new Float32Array(2)); // Fails
Messages
assert.isFloat64Array.message = "Expected ${actual} to be a Float64Array";
refute.isFloat64Array.message = "Expected ${actual} not to be a Float64Array";
isInfinity()
assert.isInfinity(actual[, message])
Fails if actual
is not Infinity
.
assert.isInfinity(Infinity); // Passes
assert.isInfinity(42); // Fails
Messages
assert.isInfinity.message = "Expected ${actual} to be Infinity";
refute.isInfinity.message = "Expected ${actual} not to be Infinity";
isInt8Array()
assert.isInt8Array(actual[, message])
Fails if actual
is not an instance of Int8Array
.
assert.isInt8Array(new Int8Array(2)); // Passes
assert.isInt8Array(new Int16Array(2)); // Fails
Messages
assert.isInt8Array.message = "Expected ${actual} to be an Int8Array";
refute.isInt8Array.message = "Expected ${actual} not to be an Int8Array";
isInt16Array()
assert.isInt16Array(actual[, message])
Fails if actual
is not an instance of Int16Array
.
assert.isInt16Array(new Int16Array(2)); // Passes
assert.isInt16Array(new Int32Array(2)); // Fails
Messages
assert.isInt16Array.message = "Expected ${actual} to be an Int16Array";
refute.isInt16Array.message = "Expected ${actual} not to be an Int16Array";
isInt32Array()
assert.isInt32Array(actual[, message])
Fails if actual
is not an instance of Int32Array
.
assert.isInt32Array(new Int32Array(2)); // Passes
assert.isInt32Array(new Int16Array(2)); // Fails
Messages
assert.isInt32Array.message = "Expected ${actual} to be an Int32Array";
refute.isInt32Array.message = "Expected ${actual} not to be an Int32Array";
isIntlCollator()
assert.isIntlCollator(actual[, message])
Fails if actual
is not an instance of Intl.Collator
.
assert.isIntlCollator(new Intl.Collator()); // Passes
assert.isIntlCollator({}); // Fails
Messages
assert.isIntlCollator.message = "Expected ${actual} to be an Intl.Collator";
refute.isIntlCollator.message = "Expected ${actual} not to be an Intl.Collator";
isIntlDateTimeFormat()
assert.isIntlDateTimeFormat(actual[, message])
Fails if actual
is not an instance of Intl.DateTimeFormat
.
assert.isIntlDateTimeFormat(new Intl.DateTimeFormat()); // Passes
assert.isIntlDateTimeFormat({}); // Fails
Messages
assert.isIntlDateTimeFormat.message =
"Expected ${actual} to be an Intl.DateTimeFormat";
refute.isIntlDateTimeFormat.message =
"Expected ${actual} not to be an Intl.DateTimeFormat";
isIntlNumberFormat()
assert.isIntlNumberFormat(actual[, message])
Fails if actual
is not an instance of Intl.NumberFormat
.
assert.isIntlNumberFormat(new Intl.NumberFormat()); // Passes
assert.isIntlNumberFormat({}); // Fails
Messages
assert.isIntlNumberFormat.message =
"Expected ${actual} to be an Intl.NumberFormat";
refute.isIntlNumberFormat.message =
"Expected ${actual} not to be an Intl.NumberFormat";
isMap()
assert.Map(actual[, message])
Fails if actual
is not an instance of Map
.
assert.isMap(new Map()); // Passes
assert.isMap({}); // Fails
Messages
assert.isMap.message = "Expected ${actual} to be a Map";
refute.isMap.message = "Expected ${actual} not to be a Map";
isPromise()
assert.Promise(actual[, message])
Fails if actual
is not an instance of Promise
.
assert.isPromise(new Promise()); // Passes
assert.isPromise({}); // Fails
Messages
assert.isPromise.message = "Expected ${actual} to be a Promise";
refute.isPromise.message = "Expected ${actual} not to be a Promise";
isRangeError()
assert.isRangeError(actual[, message])
Fails if actual
is not an instance of RangeError
.
assert.isRangeError(new RangeError("this is a range error")); // Passes
assert.isRangeError(new Error("this is not a range error")); // Fails
Messages
assert.isRangeError.message = "Expected ${actual} to be an RangeError";
refute.isRangeError.message = "Expected ${actual} not to be an RangeError";
isReferenceError()
assert.isReferenceError(actual[, message])
Fails if actual
is not an instance of ReferenceError
.
assert.isReferenceError(new ReferenceError("this is a range error")); // Passes
assert.isReferenceError(new Error("this is not a range error")); // Fails
Messages
assert.isReferenceError.message = "Expected ${actual} to be a ReferenceError";
refute.isReferenceError.message =
"Expected ${actual} not to be a ReferenceError";
isRegExp()
assert.isRegExp(actual[, message])
Fails if actual
is not an instance of RegExp
.
assert.isRegExp(new RegExp("apple pie")); // Passes
assert.isRegExp(/apple pie/); // Passes
assert.isRegExp("apple pie"); // Fails
Messages
assert.isRegExp.message = "Expected ${actual} to be an RegExp";
refute.isRegExp.message = "Expected ${actual} not to be an RegExp";
isSet()
assert.isSet(actual[, message])
Fails if actual
is not an instance of Set
.
assert.isSet(new Set()); // Passes
assert.isSet([]); // Fails
Messages
assert.isSet.message = "Expected ${actual} to be a Set";
refute.isSet.message = "Expected ${actual} not to be a Set";
isSymbol()
assert.isSymbol(actual[, message])
Fails if actual
is not a value of type Symbol
.
assert.isSymbol(Symbol("apple pie")); // Passes
assert.isSymbol("apple pie"); // Fails
Messages
assert.isSymbol.message = "Expected ${actual} to be a Symbol";
refute.isSymbol.message = "Expected ${actual} not to be a Symbol";
isSyntaxError()
assert.isSyntaxError(actual[, message])
Fails if actual
is not an instance of SyntaxError
.
assert.isSyntaxError(new SyntaxError("this is a syntax error")); // Passes
assert.isSyntaxError(new Error("this is not a syntax error")); // Fails
Messages
assert.isSyntaxError.message = "Expected ${actual} to be a SyntaxError";
refute.isSyntaxError.message = "Expected ${actual} not to be a SyntaxError";
isTypeError()
assert.isTypeError(actual[, message])
Fails if actual
is not an instance of TypeError
.
assert.isTypeError(new TypeError("this is a type error")); // Passes
assert.isTypeError(new Error("this is not a type error")); // Fails
Messages
assert.isTypeError.message = "Expected ${actual} to be a TypeError";
refute.isTypeError.message = "Expected ${actual} not to be a TypeError";
isURIError()
assert.isURIError(actual[, message])
Fails if actual
is not an instance of URIError
.
assert.isURIError(new URIError("this is a uri error")); // Passes
assert.isURIError(new Error("this is not a uri error")); // Fails
Messages
assert.isURIError.message = "Expected ${actual} to be a URIError";
refute.isURIError.message = "Expected ${actual} not to be a URIError";
isUint16Array()
assert.isUint16Array(actual[, message])
Fails if actual
is not an instance of Uint16Array
.
assert.isUint16Array(new Uint16Array()); // Passes
assert.isUint16Array(new Uint32Array()); // Fails
assert.isUint16Array(new Uint8Array()); // Fails
Messages
assert.isUint16Array.message = "Expected ${actual} to be a Uint16Array";
refute.isUint16Array.message = "Expected ${actual} not to be a Uint16Array";
isUint32Array()
assert.isUint32Array(actual[, message])
Fails if actual
is not an instance of Uint32Array
.
assert.isUint32Array(new Uint16Array()); // Fails
assert.isUint32Array(new Uint32Array()); // Passes
assert.isUint32Array(new Uint8Array()); // Fails
Messages
assert.isUint32Array.message = "Expected ${actual} to be a Uint32Array";
refute.isUint32Array.message = "Expected ${actual} not to be a Uint32Array";
isUint8Array()
assert.isUint8Array(actual[, message])
Fails if actual
is not an instance of Uint8Array
.
assert.isUint8Array(new Uint16Array()); // Fails
assert.isUint8Array(new Uint32Array()); // Fails
assert.isUint8Array(new Uint8Array()); // Passes
Messages
assert.isUint8Array.message = "Expected ${actual} to be a Uint8Array";
refute.isUint8Array.message = "Expected ${actual} not to be a Uint8Array";
isUint8ClampedArray()
assert.isUint8ClampedArray(actual[, message])
Fails if actual
is not an instance of Uint8ClampedArray
.
assert.isUint8ClampedArray(new Uint8ClampedArray()); // Passes
assert.isUint8ClampedArray(new Uint8Array()); // Fails
Messages
assert.isUint8ClampedArray.message =
"Expected ${actual} to be a Uint8ClampedArray";
refute.isUint8ClampedArray.message =
"Expected ${actual} not to be a Uint8ClampedArray";
isWeakMap()
assert.isWeakMap(actual[, message])
Fails if actual
is not an instance of WeakMap
.
assert.isWeakMap(new WeakMap()); // Passes
assert.isWeakMap(new Map()); // Fails
Messages
assert.isWeakMap.message = "Expected ${actual} to be a WeakMap";
refute.isWeakMap.message = "Expected ${actual} not to be a WeakMap";
isWeakSet()
assert.isWeakSet(actual[, message])
Fails if actual
is not an instance of WeakSet
.
assert.isWeakSet(new WeakSet()); // Passes
assert.isWeakSet(new Set()); // Fails
Messages
assert.isWeakSet.message = "Expected ${actual} to be a WeakSet";
refute.isWeakSet.message = "Expected ${actual} not to be a WeakSet";
keys()
assert.keys(object, keyArray[, message])
Fails if object’s own properties are not exactly the same as a given list.
assert.keys({ test1: "t1", test2: "t2" }, ["test1"]); // Fails - 'test2' is unexpected
assert.keys({ test1: "t1", test2: "t2" }, ["test1", "test2", "test3"]); // Fails - 'test3' is not present
assert.keys({ test1: "t1", test2: "t2" }, ["test1", "test2"]); // Passes
Messages
assert.keys.message = "Expected ${actualObject} to have exact keys ${keys}";
refute.keys.message = "Expected not to have exact keys ${keys}";
exception()
assert.exception(callback[, matcher, message])
Fails if callback
does not throw an exception. If the optional matcher
is provided, the assertion fails if the callback either does not throw an exception, or if the exception does not meet the criterias of the given matcher
.
The matcher
can be of type object
or function
. If the matcher
is of type object
, the captured error object and the matcher
are passed to match()
.
If the matcher
is of type function
, the captured error object is passed as argument to the matcher
function, which has to return true
for a matching error object, otherwise false
.
// Passes
assert.exception(function () {
throw new Error("Ooops!");
});
// Fails
assert.exception(function () {});
// Passes
assert.exception(
function () {
throw new TypeError("Ooops!");
},
{ name: "TypeError" },
);
// Fails, wrong exception type
assert.exception(
function () {
throw new Error("Aww");
},
{ name: "TypeError" },
);
// Fails, wrong exception message
assert.exception(
function () {
throw new Error("Aww");
},
{ message: "Ooops!" },
);
// Fails, wrong exception type
assert.exception(
function () {
throw new Error("Aww");
},
function (err) {
if (err.name !== "TypeError") {
return false;
}
return true;
},
"Type of exception is wrong!",
); // with message to print, if test fails
near()
assert.near(actual, expected, delta[, message])
Fails if the difference between actual
and expected
is greater than delta
.
assert.near(10.3, 10, 0.5); // Passes
assert.near(10.5, 10, 0.5); // Passes
assert.near(10.6, 10, 0.5); // Fails
Messages
assert.near.message =
"Expected ${actual} to be equal to ${expected} +/- ${delta}";
refute.near.message =
"Expected ${actual} not to be equal to ${expected} +/- ${delta}";
hasArity()
assert.hasArity(actual, arity[, message])
Fails when actual
does not have the desired arity.
assert.hasArity(function (one) {
return one;
}, 1); // Passes
assert.hasArity(function (one, two) {
return one + two;
}, 2); // Passes
assert.hasArity(function (one, two) {
return one + two;
}, 1); // Fails
Messages
assert.hasArity.message =
"Expected ${name} to have arity of ${1} but was ${arity}";
refute.hasArity.message = "Expected ${name} to not have arity of ${1}";
hasPrototype()
assert.hasPrototype(actual, prototype[, message])
Fails if prototype
does not exist in the prototype chain of actual
.
assert.hasPrototype(function () {}, Function.prototype); // Passes
assert.hasPrototype(function () {}, Object.prototype); // Passes
assert.hasPrototype({}, Function.prototype); // Fails
Messages
assert.hasPrototype.message =
"Expected ${actual} to have ${expected} on its prototype chain";
refute.hasPrototype.message =
"Expected ${actual} not to have ${expected} on its prototype chain";
contains()
assert.contains(haystack, needle[, message])
Fails if the array like object haystack
does not contain the needle
argument.
assert.contains([1, 2, 3], 2); // Passes
assert.contains([1, 2, 3], 4); // Fails
assert.contains([1, 2, 3], "2"); // Fails
Messages
assert.contains.message = "Expected [${actual}] to contain ${expected}";
refute.contains.message = "Expected [${actual}] not to contain ${expected}";
tagName()
assert.tagName(element, tagName[, message])
Fails if the element
either does not specify a tagName
property, or if its value is not a case-insensitive match with the expected tagName
. Works with any object.
assert.tagName(document.createElement("p"), "p"); // Passes
assert.tagName(document.createElement("h2"), "H2"); // Passes
assert.tagName(document.createElement("p"), "li"); // Fails
className()
assert.className(element, classNames[, message])
Fails if the element
either does not specify a className
property, or if its value is not a space-separated list of all class names in classNames
.
classNames
can be either a space-delimited string or an array of class names. Every class specified by classNames must be found in the object’s className
property for the assertion to pass, but order does not matter.
var el = document.createElement("p");
el.className = "feed item blog-post";
assert.className(el, "item"); // Passes
assert.className(el, "news"); // Fails
assert.className(el, "blog-post feed"); // Passes
assert.className(el, "feed items"); // Fails, "items" is not a match
assert.className(el, ["item", "feed"]); // Passes
resolves()
assert.resolves(promise[, value])
NOTE: This assertion returns a Promise!
The assertion resolves, if the value resolved from promise
equals
the given value
.
Furthermore, the assertion rejects if,
- the resolved value from the input
promise
is not equal to the givenvalue
- the given
promise
rejects instead of resolving - the given input is not a Promise
NOTE: In order to tell the test runner to wait until the assertion has completed, you either need to return the Promise from the assertion:
test("some asynchronous code", function() {
return assert.resolves(myAsyncFunc(), {...});
});
or use async
/await
:
test("some asynchronous code", async function() {
await assert.resolves(myAsyncFunc(), {...});
});
rejects()
assert.rejects(promise[, value])
NOTE: This assertion returns a Promise!
The assertion resolves, if the value rejected from promise
equals
the given value
.
Furthermore, the assertion rejects if,
- the rejected value from the input
promise
is not equal to the givenvalue
- the given
promise
resolves instead of rejecting - the given input is not a Promise
NOTE: In order to tell the test runner to wait until the assertion has completed, you either need to return the Promise from the assertion:
test("some asynchronous code", function() {
return assert.rejects(myAsyncFunc(), {...});
});
or use async
/await
:
test("some asynchronous code", async function() {
await assert.rejects(myAsyncFunc(), {...});
});
json()
assert.json(actual, json[, message])
Fails if actual
is not valid JSON or the parsed JSON is not equal to json
. Uses the same comparison algorithm as equals()
.
var serialized = JSON.stringify({ is: 42 });
assert.json(serialized, { is: 42 }); // Passes
assert.json(serialized, { or: 42 }); // Fails
assert.json(serialized, { is: 7 }); // Fails
assert.json("no-json", {}); // Fails
matchJson()
assert.matchJson(actual, json[, message])
Fails if actual
is not valid JSON or the parsed JSON does not match json
. Uses the same matcher algorithm as match()
.
var serialized = JSON.stringify({ is: 42, and: 3 });
assert.matchJson(serialized, { is: 42 }); // Passes
assert.matchJson(serialized, { and: 3 }); // Passes
assert.matchJson(serialized, { or: 42 }); // Fails
assert.matchJson(serialized, { is: 7 }); // Fails
assert.matchJson("no-json", {}); // Fails
Custom assertions
Custom, domain-specific assertions help improve clarity and reveal intent in tests. They also facilitate much better feedback when they fail. You can add custom assertions that behave exactly like the built-in ones (i.e. with counting, message formatting, expectations and
more) by using the referee.add
method.
Load custom assertions
Custom assertions can be loaded as modules using e.g. mocha to be used in tests.
Custom assertion
./test/assertions/is-prime.js
const referee = require("referee");
// adapted from https://stackoverflow.com/a/40200710
function isPrime(number) {
for (var i = 2; i < number; i++) {
if (number % i === 0) {
return false;
}
}
return number !== 1 && number !== 0;
}
referee.add("isPrime", {
assert: function assert(actual) {
if (typeof actual !== "number" || actual < 0) {
throw new TypeError("'actual' argument should be a non-negative Number");
}
this.actual = actual;
return isPrime(actual);
},
assertMessage: "Expected ${actual} to be a prime number",
refuteMessage: "Expected ${actual} to not be a prime number",
expectation: "toHaveArity",
});
Test
./test/some.test.js
const { assert, refute } = require("referee");
describe("some", function () {
it("should have isPrime installed", function () {
assert.isPrime(5);
refute.isPrime(6);
});
});
Execute
mocha -r ./test/assetions/*
This repository hosts the full runnable example from above, as well as demos using other popular test runners.
Overriding assertion messages
The default assertion messages can be overridden. The messages to
overwrite are listed with each assertion. You can use the same keys for
string interpolation (e.g. ${actual}
, ${expected}
). equals:
var assert = require("referee").assert;
assert.equals.message = "I wanted ${actual} == ${expected}!";
try {
assert.equals(3, 4);
} catch (e) {
console.log(e.message);
}
// Prints:
// "I wanted 3 == 4!"
Events
referee is an event-emitter. Listen to events with on
:
referee.on("failure", function (err) {
console.log(err.message);
});
pass
event
Signature:
"pass", function () {};
Assertion passed. The callback is invoked with the assertion name, e.g.
"equals"
, as its only argument. Note that this event is also emitted
when refutations pass.
failure
event
Signature:
"failure", function (error) {};
Assertion failed. The callback is invoked with an AssertionError
object.
Expectations
All of referee's assertions and refutations are also exposed as "expectations". Expectations is just a slightly different front-end to the same functionality, often preferred by the BDD inclined.
Expectations mirror assertions under different names. Refutations can be expressed using expect(obj).not
and then calling either of the expectations on the resulting object.
var expect = require("referee").expect;
expect({ id: 42 }).toBeObject(); // Passes
expect("Somewhere in here").toMatch("in"); // Passes
expect(42).not.toEqual(43); // Passes
expect.toBe()
expect(actual).toBe(expected);
See same()
expect.toEqual()
expect(actual).toEqual(expected);
See equals()
expect.toBeGreaterThan()
expect(actual).toBeGreaterThan(expected);
See greater()
expect.toBeLessThan()
expect(actual).toBeLessThan(expected);
See less()
expect.toBeDefined()
expect(actual).toBeDefined(expected);
See defined()
expect.toBeNull()
expect(actual).toBeNull(expected);
See isNull()
expect.toMatch()
expect(actual).toMatch(expected);
See match()
expect.toBeObject()
expect(actual).toBeObject(expected);
See isObject()
expect.toBeFunction()
expect(actual).toBeFunction(expected);
See isFunction()
expect.toBeTrue()
expect(actual).toBeTrue();
See isTrue()
expect.toBeFalse()
expect(actual).toBeFalse();
See isFalse()
expect.toBeString()
expect(actual).toBeString();
See isString()
expect.toBeBoolean()
expect(actual).toBeBoolean();
See isBoolean()
expect.toBeNumber()
expect(actual).toBeNumber();
See isNumber()
expect.toBeNaN()
expect(actual).toBeNaN();
See isNaN()
expect.toBeArray()
expect(actual).toBeArray();
See isArray()
expect.toBeArrayLike()
expect(actual).toBeArrayLike();
See isArrayLike()
expect.toHaveKeys()
expect(object).toHaveKeys(keyArray);
See keys()
expect.toThrow()
expect(actual).toThrow(expected);
See exception()
expect.toBeNear()
expect(actual).toBeNear(expected, delta);
See near()
expect.toHavePrototype()
expect(actual).toHavePrototype(prototype);
See hasPrototype()
expect.toContain()
expect(haystack).toContain(needle);
See contains()
expect.toHaveTagName()
expect(actual).toHaveTagName(expected);
See tagName()
expect.toHaveClassName()
expect(actual).toHaveClassName(expected);
See className()
expect.toEqualJson()
expect(actual).toEqualJson(expected);
See json()
expect.toMatchJson()
expect(actual).toMatchJson(expected);
See matchJson()
expect.toHaveBeenCalled()
expect(spy).toHaveBeenCalled();
See called()
expect.toHaveBeenCalledOnce()
expect(spy).toHaveBeenCalledOnce(expected);
See calledOnce()
expect.toHaveBeenCalledTwice()
expect(spy).toHaveBeenCalledTwice(expected)
See calledTwice()
expect.toHaveBeenCalledThrice()
expect(spy).toHaveBeenCalledThrice(expected);
See calledThrice()
expect.toHaveBeenCalledWith()
expect(spy).toHaveBeenCalledWith(arg1, arg2, ...)
See calledWith()
expect.toHaveBeenCalledOnceWith()
expect(spy).toHaveBeenCalledOnceWith(arg1, arg2, ...)
See calledOnceWith()
Methods
referee.fail()
referee.fail(message);
When an assertion fails, it calls referee.fail()
with the failure message as the only argument. The built-in fail
function both throws an AssertionError()
and emits it to the failure
event. The error can be caught and handled by the test runner. If this behavior is not suitable for your testing framework of choice, you can override referee.fail()
to make it do the right thing.
Example: To use referee with JsTestDriver, you can simply configure it as follows:
referee.fail = function (message) {
fail(message);
};
Where the global fail
function is the one provided by JsTestDriver.
It is possible to make the default assert.fail
method only emit an event and not throw an error. This may be suitable in asynchronous test runners, where you might not be able to catch exceptions. To silence exceptions, see the throwOnFailure
property.
referee.add()
referee.add(name, options);
Add a custom assertion. Using this ‘macro’ to add project specific assertions has a few advantages:
- Assertions will be counted
- Failure messages will have interpolated arguments formatted
- A single function generates both an assertion and a refutation
- If using expectations, an expectation can easily be generated as well
- When
failOnNoAssertions
is set totrue
, the assertion will behave correctly (may be important for asynchronous tests) - The assertion will fail if too few arguments are passed
Here’s an example of adding a “foo” assertion, that only passes when its only argument is the string “foo”:
var assert = referee.assert;
var refute = referee.refute;
var expect = referee.expect;
referee.add("isFoo", {
assert: function (actual) {
return actual == "foo";
},
assertMessage: "Expected ${0} to be foo!",
refuteMessage: "Expected not to be foo!",
expectation: "toBeFoo",
});
// Now you can do:
// Passes
assert.isFoo("foo");
// Fails: "[assert.isFoo] Expected { id: 42 } to be foo!"
assert.isFoo({ id: 42 });
// Fails: "[refute.isFoo] Expected not to be foo!"
refute.isFoo("foo");
// Passes
expect("foo").toBeFoo();
// To support custom messages, do this:
referee.add("isFoo", {
assert: function (actual) {
return actual == "foo";
},
assertMessage: "${1}Expected ${0} to be foo!",
refuteMessage: "${1}Expected not to be foo!",
expectation: "toBeFoo",
values: function (thing, message) {
return [thing, message ? message + " " : ""];
},
});
// Fails: "[assert.isFoo] Ouch: Expected { id: 42 } to be foo!"
assert.isFoo({ id: 42 }, "Ouch");
Error message value interpolation
Arguments are available in assertion failure messages using the "${n}"
switches, where n
is a number. You can also use named variables by setting properties on this
in the assertion/refutation function:
referee.add("isString", {
assert: function (actual) {
this.actualType = typeof actual;
return this.actualType == "string";
},
assertMessage: "Expected ${0} (${actualType}) to be string",
refuteMessage: "Expected not to be string",
expectation: "toBeString",
});
Arguments
- name
- The name of the new assertion/refutation
- options
-
assert
-
The verification function. Should return
true
when the assertion passes. The generated refutation will pass when the function returnsfalse
. In some cases the refutation may not be the exact opposite of the assertion. If that is the case you should provideoptions.refute
for the custom refutation. The number of formal parameters the function accepts determines the number of required arguments to the function. If the assertion is called with less arguments than expected, referee will fail it before your custom function is even called. All arguments are available for interpolation into the resulting error message. The first argument will be available as"${0}"
, the second as"${1}"
and so on. If you want to embed other values than exact arguments into the string, you can set properties on this in the custom assertion, and refer to them as"${name}"
in the message. refute
- Custom refutation function. Used over
!assert()
if provided. assertMessage
- The error message to use when the assertion fails. The message may refer to arguments through switches like
"${0}"
and so on (see above, under the assert argument). The message is exposed on the generated assertion as the propertyassert.[name].message
. refuteMessage
- Like
assertMessage
, but for refutations. Exposed asrefute.[name].message
. values
- A function that maps values to be interpolated into the failure messages. This can be used when you need something more/else than the actual
arguments
in order. expectation
- The name of the assertion as an expectation, e.g. “toBeSomething”. Optional.
referee.verifier()
Creates a verifier function with the signature verify([expected])
.
It exposes verify.count
which is incremented every time referee
emits a "pass"
or a "failure"
event. When called, the function verifies that assertions have been made, throwing an exception if verify.count
is zero. When expected
is passed, then this is compared with verify.count
.
verify()
always unsubscribes the event listeners, so that verify.count
does not change. This means you have to create a new verifier for each test run.
it("should do something", function () {
var verify = referee.verifier();
var limit = 10;
for (var i = 0; i < 10; i++) {
console.log(i);
}
// this test will fail as no assertions have been made
verify();
});
it("should do something", function () {
var verify = referee.verifier();
var limit = 10;
for (var i = 0; i < 10; i++) {
assert.isTrue(true);
}
// this will pass because exactly 10 (`limit`) assertions have been made
verify(limit);
console.log(verify.count);
// 10
});
Properties
referee.throwOnFailure
Boolean
.
When using the default referee.fail()
implementation, this property can be set to false
to make assertion failures not throw exceptions (i.e. only emit events). This may be suitable in asynchronous test runners, where you might not be able to catch exceptions.
Supporting objects
class AssertionError()
An exception (specifically, an Error
object) whose name
property is "AssertionError"
.