.. default-domain:: js .. highlight:: javascript .. _referee: ======= referee ======= Module: ``require("referee");`` In browsers: ``buster.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 :ref:`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. .. _assertions_and_refutations: 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 = buster.referee.assert; // or short: buster.assert var refute = buster.referee.refute; // or short: buster.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. .. function:: 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 .. function:: 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:* - :func:`same` - :func:`equals` - :func:`greater` - :func:`less` - :func:`defined` - :func:`isNull` - :func:`match` - :func:`isObject` - :func:`isFunction` - :func:`isTrue` - :func:`isFalse` - :func:`isString` - :func:`isBoolean` - :func:`isNumber` - :func:`isNaN` - :func:`isArray` - :func:`isArrayLike` - :func:`exception` - :func:`near` - :func:`hasPrototype` - :func:`contains` - :func:`tagName` - :func:`className` .. function:: 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 :func:`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}"; .. function:: 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 does 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. :: assert.equals({ name: "Professor Chaos" }, { name: "Professor Chaos" }); // Passes assert.equals({ name: "Professor Chaos" }, { name: "Dr Evil" }); // Fails **Messages** :: assert.equals.message = "${actual} expected to be equal to ${expected}"; refute.equals.message = "${actual} expected not to be equal to ${expected}"; .. function:: 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}"; .. function:: 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}"; .. function:: defined :: assert.defined(object[, message]) Fails if ``object`` is ``undefined``. :: var a; assert.defined({}); // Passes assert.defined(a); // Fails **Messages** :: assert.defined.message = "Expected to be defined"; refute.defined.message = "Expected ${actual} (${actualType}) not to be defined"; ``${actualType}``: ``typeof object`` .. function:: isNull :: assert.isNull(object[, message]) Fails if ``object`` is not ``null``. :: assert.isNull(null, "This will pass"); assert.isNull({}, "This will fail"); assert.isNull(null); // Passes assert.isNull({}); // Fails **Messages** :: assert.isNull.message = "Expected ${actual} to be null"; refute.isNull.message = "Expected not to be null"; .. function:: 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" }); **Messages** :: assert.match.exceptionMessage = "${exceptionMessage}"; refute.match.exceptionMessage = "${exceptionMessage}"; Used when the matcher function throws an exception. This happens if the matcher is not any of the accepted types, for instance, a boolean. :: assert.match.message = "${actual} expected to match ${expected}"; refute.match.message = "${actual} expected not to match ${expected}"; .. function:: 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"; ``${actualType}``: ``typeof object`` .. function:: 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"; ``${actualType}`` ``typeof actual value`` .. 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"; .. function:: 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"; .. function:: 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"; ``${actualType}``: The type of the actual value .. function:: 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"; ``${actualType}``: The type of the actual value .. function:: 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"; ``${actualType}``: The type of the actual value .. function:: 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"; .. function:: 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"; .. function:: isArrayLike :: assert.isArrayLike(actual[, message]) Fails if none of the following conditions is fulfilled: - the object type of ``actual`` is ``Array`` - ``actual`` is an ``arguments`` object - ``actual`` is an object providing a property ``length`` of type ``"number"`` and a property ``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"; .. function:: 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}"; .. function:: 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 :func:`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 **Messages** :: assert.exception.typeNoExceptionMessage = "Expected ${expected} but no exception was thrown"; assert.exception.message = "Expected exception"; assert.exception.typeFailMessage = "Expected ${expected} but threw ${actualExceptionType} (${actualExceptionMessage})\n${actualExceptionStack}"; assert.exception.matchFailMessage = "Expected thrown ${actualExceptionType} (${actualExceptionMessage}) to pass matcher function"; refute.exception.message = "Expected not to throw but threw ${actualExceptionType} (${actualExceptionMessage})"; .. function:: 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}"; .. function:: 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"; ``${expected}``: The ``prototype`` object .. function:: contains :: assert.contains(haystack, needle[, message]) Fails if the array like object ``haystack`` does not contain the ``needle`` object. :: 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}"; ``${actual}``: The ``haystack`` object ``${expected}``: The ``needle`` object .. function:: 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 **Messages** :: assert.tagName.noTagNameMessage = "Expected ${actualElement} to have tagName property"; assert.tagName.message = "Expected tagName to be ${expected} but was ${actual}"; refute.tagName.noTagNameMessage = "Expected ${actualElement} to have tagName property"; refute.tagName.refuteMessage = "Expected tagName not to be ${actual}"; .. function:: className :: assert.className(element, className[, 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 **Messages** :: assert.className.noClassNameMessage = "Expected object to have className property"; assert.className.message = "Expected object's className to include ${expected} but was ${actual}"; refute.className.noClassNameMessage = "Expected object to have className property"; refute.className.message = "Expected object's className not to include ${expected}"; Custom assertions ================= Custom, domain-specific assertions helps 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 :func:`referee.add` method. 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}``). :func:`equals`:: var assert = buster.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 ====== ``buster.referee`` is an :ref:`event-emitter`. Listen to events with ``on``:: buster.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 :class:`AssertionError` object. .. _stubs-and-spies: Stubs and spies =============== The default Buster.JS bundle comes with built-in spies, stubs and mocks provided by `Sinon.JS `_. The assertions are indisposable when working with spies and stubs. However, note that these assertions are technically provided by the integration package :ref:`buster-sinon`, *not* **referee**. This only matters if you use this package stand-alone. As for the normal assertions, the assertions for stubs and spies can be used with ``assert`` and ``refute``. The description is for ``assert``, but the corresponding failure messages for ``refute`` are also mentioned. For ``refute`` the behaviour is exactly opposed. *Overview:* - :func:`called` - :func:`callOrder` - :func:`calledOnce` - :func:`calledTwice` - :func:`calledThrice` - :func:`calledOn` - :func:`alwaysCalledOn` - :func:`calledWith` - :func:`alwaysCalledWith` - :func:`calledOnceWith` - :func:`calledWithExactly` - :func:`alwaysCalledWithExactly` - :func:`threw` - :func:`alwaysThrew` .. function:: called :: assert.called(spy) Fails if the ``spy`` has never been called. :: var spy = this.spy(); assert.called(spy); // Fails spy(); assert.called(spy); // Passes spy(); assert.called(spy); // Passes **Messages** :: assert.called.message = "Expected ${0} to be called at least once but was never called"; ``${0}``: The spy :: refute.called.message = "Expected ${0} to not be called but was called ${1}${2}"; ``${0}``: The ``spy`` ``${1}``: The number of calls as a string. Ex: "two times". ``${2}``: All calls formatted as a multi-line string. .. function:: callOrder :: assert.callOrder(spy, spy2, ...) Fails if the spies were not called in the specified order. :: var spy1 = this.spy(); var spy2 = this.spy(); var spy3 = this.spy(); spy1(); spy2(); spy3(); assert.callOrder(spy1, spy3, spy2); // Fails assert.callOrder(spy1, spy2, spy3); // Passes **Messages** :: assert.callOrder.message = "Expected ${expected} to be called in order but were called as ${actual}"; refute.callOrder.message = "Expected ${expected} not to be called in order"; ``${expected}``: A string representation of the expected call order ``${actual}``: A string representation of the actual call order .. function:: calledOnce :: assert.calledOnce(spy) Fails if the ``spy`` has never been called or if it was called more than once. :: var spy = this.spy(); assert.calledOnce(spy); // Fails spy(); assert.calledOnce(spy); // Passes spy(); assert.calledOnce(spy); // Fails **Messages** :: assert.calledOnce.message = "Expected ${0} to be called once but was called ${1}${2}"; refute.calledOnce.message = "Expected ${0} to not be called exactly once${2}"; ``${0}``: The ``spy`` ``${1}``: The number of calls, as a string. Ex: "two times" ``${2}``: The call log. All calls as a string. Each line is one call and includes passed arguments, returned value and more. .. function:: calledTwice :: assert.calledTwice(spy) Only passes if the ``spy`` was called exactly two times. :: var spy = this.spy(); assert.calledTwice(spy); // Fails spy(); assert.calledTwice(spy); // Fails spy(); assert.calledTwice(spy); // Passes spy(); assert.calledTwice(spy); // Fails **Messages** :: assert.calledTwice.message = "Expected ${0} to be called twice but was called ${1}${2}"; refute.calledTwice.message = "Expected ${0} to not be called exactly twice${2}"; ``${0}``: The ``spy`` ``${1}``: The number of calls, as a string. Ex: "two times" ``${2}``: The call log. All calls as a string. Each line is one call and includes passed arguments, returned value and more. .. function:: calledThrice :: assert.calledThrice(spy) Only passes if the ``spy`` has been called exactly three times. :: var spy = this.spy(); assert.calledThrice(spy); // Fails spy(); assert.calledThrice(spy); // Fails spy(); assert.calledThrice(spy); // Passes spy(); assert.calledThrice(spy); // Fails **Messages** :: assert.calledThrice.message = "Expected ${0} to be called thrice but was called ${1}${2}"; refute.calledThrice.message = "Expected ${0} to not be called exactly thrice${2}"; ``${0}``: The ``spy`` ``${1}``: The number of calls, as a string. Ex: "two times" ``${2}``: The call log. All calls as a string. Each line is one call and includes passed arguments, returned value and more. .. function:: calledOn :: assert.calledOn(spy, obj) Passes if the ``spy`` was called at least once with ``obj`` as its ``this`` value. :: var spy = this.spy(); var obj1 = {}; var obj2 = {}; var obj3 = {}; spy.call(obj2); spy.call(obj3); assert.calledOn(spy, obj1); // Fails assert.calledOn(spy, obj2); // Passes assert.calledOn(spy, obj3); // Passes **Messages** :: assert.calledOn.message = "Expected ${0} to be called with ${1} as this but was called on ${2}"; refute.calledOn.message = "Expected ${0} not to be called with ${1} as this"; ``${0}``: The ``spy`` ``${1}``: The object ``obj`` which is expected to have been ``this`` at least once ``${2}``: List of objects which actually have been ``this`` .. function:: alwaysCalledOn :: assert.alwaysCalledOn(spy, obj) Passes if the ``spy`` was always called with ``obj`` as its ``this`` value. :: var spy1 = this.spy(); var spy2 = this.spy(); var obj1 = {}; var obj2 = {}; spy1.call(obj1); spy1.call(obj2); spy2.call(obj2); spy2.call(obj2); assert.alwaysCalledOn(spy1, obj1); // Fails assert.alwaysCalledOn(spy1, obj2); // Fails assert.alwaysCalledOn(spy2, obj1); // Fails assert.alwaysCalledOn(spy2, obj2); // Passes **Messages** :: assert.alwaysCalledOn.message = "Expected ${0} to always be called with ${1} as this but was called on ${2}"; refute.alwaysCalledOn.message = "Expected ${0} not to always be called with ${1} as this"; ``${0}``: The ``spy`` ``${1}``: The object ``obj`` which is expected always to have been ``this`` ``${2}``: List of objects which actually have been ``this`` .. function:: calledWith :: assert.calledWith(spy, arg1, arg2, ...) Passes if the ``spy`` was called at least once with the specified arguments. Other arguments may have been passed after the specified ones. :: var spy = this.spy(); var arr = [1, 2, 3]; spy(12); spy(42, 13); spy("Hey", arr, 2); assert.calledWith(spy, 12); // Passes assert.calledWith(spy, "Hey"); // Passes assert.calledWith(spy, "Hey", 12); // Fails assert.calledWith(spy, "Hey", arr); // Passes **Messages** :: assert.calledWith.message = "Expected ${0} to be called with arguments ${1}${2}"; refute.calledWith.message = "Expected ${0} not to be called with arguments ${1}${2}"; ``${0}``: The ``spy`` ``${1}``: The expected arguments ``${2}``: String representation of all calls. .. function:: alwaysCalledWith :: assert.alwaysCalledWith(spy, arg1, arg2, ...) Passes if the ``spy`` was always called with the specified arguments. Other arguments may have been passed after the specified ones. :: var spy = this.spy(); var arr = [1, 2, 3]; spy("Hey", arr, 12); spy("Hey", arr, 13); assert.alwaysCalledWith(spy, "Hey"); // Passes assert.alwaysCalledWith(spy, "Hey", arr); // Passes assert.alwaysCalledWith(spy, "Hey", arr, 12); // Fails **Messages** :: assert.alwaysCalledWith.message = "Expected ${0} to always be called with arguments ${1}${2}"; refute.alwaysCalledWith.message = "Expected ${0} not to always be called with arguments${1}${2}"; ``${0}``: The ``spy`` ``${1}``: The expected arguments ``${2}``: String representation of all calls. .. function:: calledOnceWith :: assert.calledOnceWith(spy, arg1, arg2, ...) Passes if the ``spy`` was called exactly once and with the specified arguments. Other arguments may have been passed after the specified ones. :: var spy = this.spy(); var arr = [1, 2, 3]; spy(12); assert.calledOnceWith(spy, 12); // Passes assert.calledOnceWith(spy, 42); // Fails spy(42, 13); assert.calledOnceWith(spy, 42, 13); // Fails **Messages** :: assert.calledOnceWith.message = "Expected ${0} to be called once with arguments ${1}${2}"; refute.calledOnceWith.message = "Expected ${0} not to be called once with arguments ${1}${2}"; ``${0}``: The ``spy`` ``${1}``: The expected arguments ``${2}``: String representation of all calls. .. function:: calledWithExactly :: assert.calledWithExactly(spy, arg1, arg2, ...) Passes if the ``spy`` was called at least once with exact the arguments specified. :: var spy = this.spy(); var arr = [1, 2, 3]; spy("Hey", arr, 12); spy("Hey", arr, 13); assert.calledWithExactly(spy, "Hey", arr, 12); // Passes assert.calledWithExactly(spy, "Hey", arr, 13); // Passes assert.calledWithExactly(spy, "Hey", arr); // Fails assert.calledWithExactly(spy, "Hey"); // Fails **Messages** :: assert.calledWithExactly.message = "Expected ${0} to be called with exact arguments ${1}${2}"; refute.calledWithExactly.message = "Expected ${0} not to be called with exact arguments${1}${2}"; ``${0}``: The ``spy`` ``${1}``: The expected arguments ``${2}``: String representation of all calls. .. function:: alwaysCalledWithExactly :: assert.alwaysCalledWithExactly(spy, arg1, arg2, ...) Passes if the ``spy`` was always called with exact the arguments specified. :: var spy = this.spy(); var arr = [1, 2, 3]; spy("Hey", arr, 12); assert.alwaysCalledWithExactly(spy, "Hey", arr, 12); // Passes assert.alwaysCalledWithExactly(spy, "Hey", arr); // Fails assert.alwaysCalledWithExactly(spy, "Hey"); // Fails spy("Hey", arr, 13); assert.alwaysCalledWithExactly(spy, "Hey", arr, 12); // Fails **Messages** :: assert.alwaysCalledWithExactly.message = "Expected ${0} to always be called with exact arguments ${1}${2}"; refute.alwaysCalledWithExactly.message = "Expected ${0} not to always be called with exact arguments${1}${2}"; ``${0}``: The ``spy`` ``${1}``: The expected arguments ``${2}``: String representation of all calls. .. function:: threw :: assert.threw(spy[, exception]) Passes if the ``spy`` threw at least once the specified ``exception``. The ``exception`` can be a string denoting its type, or an actual object. If ``exception`` is not specified, the assertion passes if the ``spy`` ever threw any exception. :: var exception1 = new TypeError(); var exception2 = new TypeError(); var exception3 = new TypeError(); var spy = this.spy(function(exception) { throw exception; }); function callAndCatchException(spy, exception) { try { spy(exception); } catch(e) { } } callAndCatchException(spy, exception1); callAndCatchException(spy, exception2); assert.threw(spy); // Passes assert.threw(spy, "TypeError"); // Passes assert.threw(spy, exception1); // Passes assert.threw(spy, exception2); // Passes assert.threw(spy, exception3); // Fails callAndCatchException(spy, exception3); assert.threw(spy, exception3); // Passes **Messages** :: assert.threw.message = "Expected ${0} to throw an exception${1}"; refute.threw.message = "Expected ${0} not to throw an exception${1}"; ``${0}``: The ``spy`` ``${1}``: The expected ``exception`` .. function:: alwaysThrew :: assert.alwaysThrew(spy[, exception]) Passes if the ``spy`` always threw the specified ``exception``. The ``exception`` can be a string denoting its type, or an actual object. If ``exception`` is not specified, the assertion passes if the ``spy`` ever threw any exception. :: var exception1 = new TypeError(); var exception2 = new TypeError(); var spy = this.spy(function(exception) { throw exception; }); function callAndCatchException(spy, exception) { try { spy(exception); } catch(e) { } } callAndCatchException(spy, exception1); assert.alwaysThrew(spy); // Passes assert.alwaysThrew(spy, "TypeError"); // Passes assert.alwaysThrew(spy, exception1); // Passes callAndCatchException(spy, exception2); assert.alwaysThrew(spy); // Passes assert.alwaysThrew(spy, "TypeError"); // Passes assert.alwaysThrew(spy, exception1); // Fails **Messages** :: assert.alwaysThrew.message = "Expected ${0} to always throw an exception${1}"; refute.alwaysThrew.message = "Expected ${0} not to always throw an exception${1}"; ``${0}``: The ``spy`` ``${1}``: The expected ``exception`` .. _expectations: 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 = buster.referee.expect; expect({ id: 42 }).toBeObject(); // Passes expect("Somewhere in here").toMatch("in"); // Passes expect(42).not.toEqual(43); // Passes .. function:: expect.toBe :: expect(actual).toBe(expected) See :func:`same` .. function:: expect.toEqual :: expect(actual).toEqual(expected) See :func:`equals` .. function:: expect.toBeGreaterThan :: expect(actual).toBeGreaterThan(expected) See :func:`greater` .. function:: expect.toBeLessThan :: expect(actual).toBeLessThan(expected) See :func:`less` .. function:: expect.toBeDefined :: expect(actual).toBeDefined(expected) See :func:`defined` .. function:: expect.toBeNull :: expect(actual).toBeNull(expected) See :func:`isNull` .. function:: expect.toMatch :: expect(actual).toMatch(expected) See :func:`match` .. function:: expect.toBeObject :: expect(actual).toBeObject(expected) See :func:`isObject` .. function:: expect.toBeFunction :: expect(actual).toBeFunction(expected) See :func:`isFunction` .. function:: expect.toBeTrue :: expect(actual).toBeTrue() See :func:`isTrue` .. function:: expect.toBeFalse :: expect(actual).toBeFalse() See :func:`isFalse` .. function:: expect.toBeString :: expect(actual).toBeString() See :func:`isString` .. function:: expect.toBeBoolean :: expect(actual).toBeBoolean() See :func:`isBoolean` .. function:: expect.toBeNumber :: expect(actual).toBeNumber() See :func:`isNumber` .. function:: expect.toBeNaN :: expect(actual).toBeNaN() See :func:`isNaN` .. function:: expect.toBeArray :: expect(actual).toBeArray() See :func:`isArray` .. function:: expect.toBeArrayLike :: expect(actual).toBeArrayLike() See :func:`isArrayLike` .. function:: expect.toHaveKeys :: expect(object).toHaveKeys(keyArray) See :func:`keys` .. function:: expect.toThrow :: expect(actual).toThrow(expected) See :func:`exception` .. function:: expect.toBeNear :: expect(actual).toBeNear(expected, delta) See :func:`near` .. function:: expect.toHavePrototype :: expect(actual).toHavePrototype(prototype) See :func:`hasPrototype` .. function:: expect.toContain :: expect(haystack).toContain(needle) See :func:`contains` .. function:: expect.toHaveTagName :: expect(actual).toHaveTagName(expected) See :func:`tagName` .. function:: expect.toHaveClassName :: expect(actual).toHaveClassName(expected) See :func:`className` .. function:: expect.toHaveBeenCalled :: expect(spy).toHaveBeenCalled() See :func:`called` .. function:: expect.toHaveBeenCalledOnce :: expect(spy).toHaveBeenCalledOnce(expected) See :func:`calledOnce` .. function:: expect.toHaveBeenCalledTwice :: expect(spy).toHaveBeenCalledTwice(expected) See :func:`calledTwice` .. function:: expect.toHaveBeenCalledThrice :: expect(spy).toHaveBeenCalledThrice(expected) See :func:`calledThrice` .. function:: expect.toHaveBeenCalledWith :: expect(spy).toHaveBeenCalledWith(arg1, arg2, ...) See :func:`calledWith` .. function:: expect.toHaveBeenCalledOnceWith :: expect(spy).toHaveBeenCalledOnceWith(arg1, arg2, ...) See :func:`calledOnceWith` Methods ======= .. function:: referee.fail :: buster.referee.fail(message) When an assertion fails, it calls :func:`referee.fail` with the failure message as the only argument. The built-in ``fail`` function both throws an :class:`AssertionError` and emits it to the `failure <#event-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 :func:`referee.fail` to make it do the right thing. Example: To use **referee** with JsTestDriver, you can simply configure it as follows:: buster.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 :attr:`throwOnFailure` property. .. function:: referee.format :: buster.referee.format(object) Values inserted into assertion messages using the ``${n}`` switches are formatted using :func:`referee.format`. By default this method simply coerces the object to a string. A more expressive option is to use :ref:`buster-format`, which is a generic function for formatting objects nicely as ASCII. For nice ASCII formatting of objects (including DOM elements) do:: buster.referee.format = buster.format.ascii; .. function:: referee.add :: buster.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 by :func:`referee.format`. - A single function generates both an assertion and a refutation. - If using expectations, an expectation can easily be generated as well. - When ```failOnNoAssertions`` <#failOnNoAssertions>`_ is set to ``true``, 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 = buster.referee.assert; var refute = buster.referee.refute; var expect = buster.referee.expect; buster.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: buster.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:: buster.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 returns false. In some cases the refutation may not be the exact opposite of the assertion. If that is the case you should provide ``options.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, Buster 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 property ``assert.[name].message``. ``refuteMessage``: Like ``assertFail``, but for refutations. Exposed as ``refute.[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. Properties ========== .. attribute:: referee.count Number increasing from 0. ``buster.referee.count`` is incremented anytime an assertion is called. The assertion counter can be reset to any number at your convenience. .. attribute:: throwOnFailure Boolean. When using the default :func:`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"``.