A flatter pattern for testing nested async functions
// http://jsfiddle.net/1mjzpapb/
var controller, helpers = window.unitTestHelpers;
// controller.js
(function () {
controller = {
async1: forever,
async2: forever,
async3: forever,
sync1: function () {},
sync2: function () {},
sync3: function () {},
someAsyncMethod: someAsyncMethod
};
function someAsyncMethod() {
/**/
return controller
.async1('foo')
.then(function (result) {
controller.sync1(result);
return controller.async2('bar');
})
.then(function (result) {
controller.sync2(result);
return controller.async3('baz');
})
.then(function (result) {
controller.sync3(result);
return result;
});
/**/
/** Alternatively written as:
return controller.async1('foo').then(function (result) {
controller.sync1(result);
return controller.async2('bar').then(function (result) {
controller.sync2(result);
return controller.async3('baz').then(function (result) {
controller.sync3(result);
return result;
});
});
});
/**/
}
})();
// controller.spec.js
(function () {
describe('controller', function () {
describe('#someAsyncMethod', function () {
var promiseResponse;
beforeEach(function (done) {
helpers.spies.extendObj(controller, ['sync1', 'sync2', 'sync3',
{ name: 'async1', and: { returnValue: 'test1' }, options: { promise: true }},
{ name: 'async2', and: { returnValue: 'test2' }, options: { promise: true }},
{ name: 'async3', and: { returnValue: 'test3' }, options: { promise: true }}
]);
promiseResponse = controller.someAsyncMethod();
Q.all([controller.async1, controller.async2, controller.async3]).done(done);
});
it('should call async1', function () {
expect(controller.async1).toHaveBeenCalledWith('foo');
});
it('should return the value of async3', function (done) {
promiseResponse.then(function (result) {
expect(result).toBe('test3');
done();
});
});
it('#async1 should call sync1', function () {
expect(controller.sync1).toHaveBeenCalledWith('test1');
});
it('#async1 should call async2', function () {
expect(controller.async2).toHaveBeenCalledWith('bar');
});
it('#async2 should call sync2', function () {
expect(controller.sync2).toHaveBeenCalledWith('test2');
});
it('#async2 should call async3', function () {
expect(controller.async3).toHaveBeenCalledWith('baz');
});
it('#async3 should call sync3', function () {
expect(controller.sync3).toHaveBeenCalledWith('test3');
});
});
});
})();
function forever() {
var dfd = Q.defer();
setTimeout(function () {
dfd.resolve();
}, 10000000000)
return dfd.promise;
}