Skip to content
spadgos edited this page Mar 6, 2012 · 5 revisions

Built-in Assertions

is

Assert that the subject is identical (===, same value and type) to another value.

assert.that(3).is("3")(); // FAIL, 3 === "3" is false since they are of different types
assert.that(3).is(3)();   // PASS

For comparing the members of objects (including Arrays, Dates, etc), the equals assertion usually more appropriate. For example,

assert.that([1, 2, 3]).is([1, 2, 3])();     // FAIL, they are not the same object
assert.that([1, 2, 3]).equals([1, 2, 3])(); // PASS, each of their members have the same value.

There is one special case for equality checking in Javascript, and that is when comparing to NaN. Nothing at all is equal to NaN... not even itself! It is important to know that Tyrtle normalises this behaviour.

var x = NaN;
console.log(x === NaN); // false
console.log(x === x);   // false!

assert.that(x).is(NaN)(); // PASS

Remember that is is the default assertion, and so specifying it by name in any assertion is entirely optional, even when you're using it as a function itself:

// these are equivalent

assert(x).is(3)();
assert(x)(3)();

not

Assert that two values are not identical. Uses strict equality checking: !==.

assert(3).is.not('3')(); // PASS

This assertion normalises the behaviour of NaN in the same way as is()

var x = NaN;
assert(x).not(NaN)(); // FAIL

You can also use .not as a modifier for any other assertion, even custom assertions.

assert('tyrtle').not.startsWith('t')(); // FAIL
assert('tyrtle').not.startsWith('m')(); // PASS

equals

Assert that two objects have the same values (deep equality).

This assertion should be used when you want to compare two objects to see that they contain the same values. If you are asserting with primitives such as strings or numbers, then it is faster to use .is.

assert.that({a : 'bar', b : 'baz'})
    .equals({b : 'baz', a : 'bar'})(); // PASS, same keys and values.

assert.that(3).equals(3)(); // PASS, but not as efficient

This will recursively search through nested objects.

ok

Assert that the subject variable is truthy. That is, it will pass if the condition subject == true is true. This will be the case for every value except: 0, false, '', null & undefined.

assert(5).is.ok()();     // PASS
assert([]).is.ok()();    // PASS, even empty arrays are ok
assert({}).is.ok()();    // PASS, even empty objects are ok
assert(false).is.ok()(); // FAIL

ofType

Assert the type of a variable (using the typeof operator).

Allows some types additional to the built-in native types to simplify tests:

  • 'array'
  • 'date'
  • 'regexp'
assert.that(/foo/).is.ofType('regexp')();
assert.that(new Date()).is.ofType('date')();
assert.that([]).is.ofType('array')();

It is important to note, however, that asserting type 'object' will pass for all of these types, since strictly speaking, they are still objects.

var arr = [],
    obj = {};
assert.that(arr).is.ofType('object')();  // PASS
assert.that(arr).is.ofType('array')();   // PASS
assert.that(obj).is.ofType('array')();   // FAIL

matches

Assert that a string matches a given regular expression.

assert.that("The cow jumped over the moon").matches(/cow.+moon/)();

startsWith, endsWith

Assert that a string starts or ends with a given substring.

assert.that("abcde").endsWith("de")();
assert.that("abcde").startsWith("abc")();

contains

Assert that a String or Array contains a substring or element.

assert(['a', 'b', 'c']).contains('b')(); // uses strict equality checking (===)
assert('foobarbaz').contains('bar')();

The test is performed using the .indexOf method of the subject, so it can actually apply to any object which implements this method with the same signature and return style as String.indexOf (-1 to indicate "not found").

var myObject = {
    indexOf : function (needle) {
        return needle === "what I'm looking for" ? -1 : 0;
    }
};

assert.that(myObject).contains("what I'm looking for")(); // FAIL, bad luck, Bono.
assert.that(myObject).contains("something else")();       // PASS

willThrow

Assert that a function will throw an error when executed. Additionally, a specific type of error or error message can be expected. If this is specified and an error is thrown which does not match the expectation, the assertion will fail.

Though the expected error type/message is optional, it is highly recommended to use it, otherwise if your function is failing in a way which you did not expect, that error will be swallowed and your tests will still pass.

The expectedError argument can be a string or a regex (in which case these are compared against the error's .message property), or a constructor (in which case, the thrown error should be an instance of this function).

The subject function will be executed with no arguments or context. If you require arguments, then a closure should be used. This assertion only be applied to subjects of type function.

assert.that(function () {
    (0)();
}).willThrow(TypeError)(); // PASS, error is an instanceof TypeError

assert.that(function () {
    throw "abc";
}).willThrow("abc")();     // PASS, the thrown error exactly matches the expected string

assert.that(function () {
    throw new Error("Holy Cow!");
}).willThrow(/cow/i)();    // PASS, the message of the error matches the expected regex

wontThrow

Assert that a function will not throw any errors when executed.

The subject function will be executed with no arguments or context. If you require arguments, then a closure should be used. This assertion only be applied to subjects of type function.

// create closure variables
var x = 3,
    self = this
;
assert(function () {
    return x + self.y;
}).wontThrow()();

called

Using this assertion requires use of the Myrtle mocking framework.

Assert that a function which has been spied upon by Myrtle has been called a certain number of times. This assertion takes two forms:

  1. .called(Number) asserts that the function has been called exactly this many times.
  2. .called() asserts that the function has been called at least once
// obtain a Myrtle handle
var handle = Myrtle.spy(myObj, 'myFunction');
doSomething();
assert.that(handle).called(3)();

However, when making assertions with Myrtle handles, unless you are cleaning up them in an after helper, you should use the .and function of Myrtle. This is because a failed assertion will immediately halt the execution of the test.

Myrtle.spy(myObject, 'myFunction').and(function () {
    doSomething();
    assert.that(this).called()("It should have been called at least once");
});

expect

This is a special type of assertion, in that it is not part of the assert object. The test itself (which is accessible as this inside the test body) has a method called expect which takes a single number as a value. This should be the number of assertions that you expect the test to execute. Use this to avoid the situation whereby a logic error in the test itself causes some assertions to not be executed, therefore it appears that the test is successful (since no assertions have actually failed!).

this.test("my test", function (assert) {
    this.expect(2);
    assert(3)(3).since("three is three");
    assert(3)(4);  // <-- didn't actually execute the assertion
});

Without the call to expect, the test above would have passed, which clearly was not the intention.

If you are writing asynchronous tests, the expectation is still defined in the test body, not the assertion function.

this.test("my async test", function (done) {
    this.expect(2);
    // do something asynchronously and then...
    done();
}, function (assert) {
    assert(3)(3)();
    assert('foo')('foo')();
});