In Angular everything seems to have a steep learning curve and unit testing an Angular app definitely doesn\'t escape this paradigm.
When I started with TDD and Ang
Then I came across another post, blog, stackoverflow example (you pick it I was probably there), and I saw the use of the $q library. Duh! Why set up a whole mock promise when we can just use the tool that Angular gives us. Our code looks nicer and makes more sense to look at - no ugly promise.then.mostRecent thing.
Next in the iteration of unit testing was this:
describe('Controller: Products', function () {
var//iable declarations
$scope,
$rootScope,
$q,
$controller,
productService,
PROMISE = {
resolve: true,
reject: false
},
PRODUCTS = [{},{},{}] //constant for the products that are returned by the service
;
beforeEach(function () {
module('App.Controllers.Products');
module('App.Services.Products');
});
beforeEach(inject(function (_$controller_, _$rootScope_, _$q_, _products_) {
$rootScope = _$rootScope_;
$q = _$q_;
$controller = _$controller_;
productService = _products_;
$scope = $rootScope.$new();
}));
function setupController(product, resolve) {
//Need a function so we can setup different instances of the controller
var getProducts = $q.defer();
//Set up our spies
spyOn(products, 'getProducts').andReturn(getProducts.promise);
//Initialise the controller
$controller('ProductsController', {
$scope: $scope,
products: productService
});
// Use $scope.$apply() to get the promise to resolve on nextTick().
// Angular only resolves promises following a digest cycle,
// so we manually fire one off to get the promise to resolve.
if(resolve) {
$scope.$apply(function() {
getProducts.resolve();
});
} else {
$scope.$apply(function() {
getProducts.reject();
});
}
}
describe('Resolving and Rejecting the Promise', function () {
it('should return the first PRODUCT when the promise is resolved', function () {
setupController(PRODUCTS[0], PROMISE.resolve); // Set up our controller to return the first product and resolve the promise.
expect('to return the first PRODUCT when the promise is resolved');
});
it('should return nothing when the promise is rejected', function () {
setupController(PRODUCTS[0], PROMISE.reject); // Set up our controller to return first product, but not to resolve the promise.
expect('to return nothing when the promise is rejected');
});
});
});
This started to feel like the way it should be set up. We can mock what we need to mock we can set our promise to resolve and reject so we can truly test the two possible outcomes. This feels good...