assert
If at any point you think of an experiment you'd like to try out, all of the code examples below are editable.
assert
is a power-user method that exposes how Distilled tells
whether a given test assertion should pass or fail. assert
can
be used to check whether a test will pass or fail before it's run.
If you're extending Distilled, you can even override the assert
method to
easily add your own custom behaviors.
While you probably won't interact with assert
directly most of the time
you're using Distilled, this section may still be helpful in showing exactly
when a Distilled test will pass or fail.
var suite = new Distilled(function () {});
console.log('Tests/suites expose an `assert` method: ', typeof suite.assert === 'function');
console.log('Calling assert returns a promise: ', suite.assert() instanceof Promise);
assert
uses basic value types to tell if an assertion should pass or
fail. Truthy values pass, and falsy (non-null) values fail.
xxxxxxxxxx
var suite = new Distilled(function () {});
suite.assert(null).then(function () {
console.log('Asserting `null` passes.');
});
suite.assert(undefined).then(function () {
console.log('Asserting `undefined` passes.');
});
suite.assert(true).then(function () {
console.log('Asserting `true` passes.');
});
suite.assert(false).catch(function () {
console.log('Asserting `false` fails.');
});
One of assert
's most powerful features is its ability to recursively
execute functions. This means that if assert
is passed a function,
it will asynchronously execute that function. Then it will treat the
result like a new assertion.
If the result is a basic type (see above), assert will resolve. If it's
another function, the whole process will be repeated. To maintain
compatibility with most other assertion libraries, assert
will reject
if an exception is thrown during a function call.
Recursively resolving assertions are a feature that may seem gimmicky until you start to extend Distilled and create helper methods for your tests. In that situation, you'll quickly find that being able to quickly and seamlessly wrap assertions in custom logic makes your life a lot easier -- and reduces boilerplate!
xxxxxxxxxx
var suite = new Distilled(function () {});
suite.assert(function () {
console.log('functions passed into assert are called.');
}).then(function () {
console.log('Because the function returned `undefined`, the assertion passed.');
});
suite.assert(function () {
return false;
}).catch(function () {
console.log('Because the function returned `false`, it failed.');
});
var err = new Error('An exception!');
suite.assert(function () {
throw err;
}).catch(function (result) {
console.log('If an exception is thrown, it gets intercepted as a failure: ', result === err);
});
suite.assert(function (test) {
console.log('Assertion context is passed into functions: ', test === suite);
console.log('Assertion context is set on `this`: ', this === suite);
});
Distilled is an async-first library. All assertions are resolved asynchronously, period. This means you can use Promises the exact same way as you use functions to nest assertions inside of each other.
xxxxxxxxxx
var suite = new Distilled(function () {});
suite.assert(Promise.resolve()).then(function () {
console.log('Because the promise resolved to `undefined`, the assertion passed.');
});
suite.assert(Promise.reject()).catch(function () {
console.log('Because the promise was rejected, the assertion failed.');
});
suite.assert(Promise.resolve(false)).catch(function () {
console.log('Because the promise resolved to `false` the assertion failed.');
});
Put it all together, and you can end up with some pretty crazy tests. Note that you probably don't want to write tests like this -- they're hard to read!
The point of recursively resolving tests is to allow you to eliminate boilerplate and hard to read logic from your tests, so the below code is just an example of what's possible.
xxxxxxxxxx
var suite = new Distilled(function () {});
suite.assert(function () {
return Promise.resolve(function () {
return Promise.resolve(function (test) {
console.log('Promises and functions can be infinitely nested.');
console.log('Nested functions still have the correct context.', test === suite && this === suite);
return Promise.resolve(false);
});
});
}).catch(function () {
console.log('Because the nested promises and functions eventually returned false, the test failed.');
});
suite.assert(function () {
return function () {
return function () {
return Promise.resolve(
Promise.resolve(function () {
return Promise.resolve(function () {
console.log('Promises can be nested in promises and functions in functions.');
});
As a convenience feature, assertions will time out and fail after 500 milliseconds.
This behavior can be customized by passing in a timeout
option when initializing
Distilled.
xxxxxxxxxx
var suite = new Distilled(function () {}); // Defaults to 500 milliseconds
suite.assert(new Promise(function () {}))
.catch(function () {
console.log('Promises auto-fail after timing out: ', true);
});
xxxxxxxxxx
var suite = new Distilled(function () {}, { timeout: 0 });
var failed = false;
suite.assert(new Promise(function () {}))
.catch(function () {
failed = true;
});
setTimeout(function () {
console.log('The assertion has not been rejected yet: ', failed === false);
}, 750);
Bugs
Code samples in this section demonstrate bug fixes. They're not particularly relevant to the documentation, but they help make sure that Distilled never has any regressions.
xxxxxxxxxx
var suite = new Distilled(function () {});
var error = new Error('error');
suite.assert(function () {
return Promise.resolve(function () {
throw error;
});
}).catch(function (err) {
console.log('Exceptions from recursively called functions are still thrown: ', err === error);
});