Asynchronous expressions
When an expectation needs to test something asynchronous, for instance testing the result from a promise, the expresion will resolve as undefined. At this point we don't know if the expression succeeded or failed; in order to know the actual result we simply need to use the familiar Promise/A interface supported by the expression.
var req = $.get('http://pollinimini.net/person.json');
ass(req).resolves.plain.prop('name').eq('Iván')
.then(function (result) {
console.log('expression was ok!');
})
.catch(function (error) {
ass.ok( error instanceof ass.Error );
console.error(error);
});
Note that anytime we use .then
(or .catch
) it'll get automatically registered
with the expression, normally the chained properties only take effect when the
expression reaches that point while evaluating but .then
is not an expectation,
it's part of the expression interface just like .test
or .assert
.
Caution
We divert from the Promise/A specification in that callback functions
registered with .then
will be called each and every time the
expression is resolved. The reasoning is that the .then
is targeting
the expression, which is an abstract form until it gets resolved.
Testing Promises
By using .resolves
and .rejects
we can attach expectations to a promise
object, the expression will automatically enter the async mode and will
subscribe itself to the promise object using its .then
method. Once the promise
is fulfilled (or rejected) the rest of the expression will continue resolving,
now using the value transfered by the promise.
In other words, every expectation chained after .resolves
or .rejects
will
be only tested once the promise is resolved and will mutate the subject value to
be whatever the promise resolves to.
Additionally since it's pretty common to check for equality there is a shortcut
matcher named .become()
that basically is the same as .resolves.eq()
:
ass(promise).become('foo') // <=> ass(promise).resolve.eq('foo')
Hint
When working with Mocha or Jasmine 2.x we are allowed to return a promise from a test and have it consumed before the test ends. Just return any ass expression to have it evaluated (even if it's not asynchronous).
it('should fetch page asynchronously and test it', function () {
var promise = $.get('http://google.com');
return ass(promise).resolves.string.contains('<body>');
// The test runner will wait here until promise is resolved and the
// expression has completed.
});
When the test runner doesn't support returning a Promise but has the concept of
a done
function, we can implement the test like so:
it('should fetch page asynchronously and test it', function (done) {
var promise = $.get('http://google.com');
ass(promise).resolves.string.contains('<body>').notify(done).catch(done);
});