Mike Alizade
Mike Alizade

Reputation: 55

angular unit testing advice

I'm new to unit testing with Angular and I'm having a great deal of trouble even getting starting with the testing. I have a controller that calls a service that calls a remote api to get a list of currencies, and then augments the returned object with a symbol property and assigns it to a scope variable.

I've been looking at a lot of httpBackend tutorials but the pieces aren't fitting together. I know I have to use whenGet and expectGet but still don't understand what they are and when I should use them, or even what I should be testing - the request, the response? Should they be in the beforeEach function of the it function?

the controller:

whiskyControllers.controller('currencyCtrlr', ['$scope', 'CurrencyConversion', 'UpdateMiniBasket', 'whiskyList',
    function($scope, CurrencyConversion, UpdateMiniBasket, whiskyList){

        $scope.getCurrencies = function(e){
            e.preventDefault();

            CurrencyConversion.async().then(function(d) { 

                $scope.rates = d.data.rates;

                for(var i = 0, j = $scope.rates.length; i < j; i++){
                    $scope.rates[i]['symbol'] = insertSymbol($scope.rates[i].to);
                }
            });
        }
}]);

I've copied the bulk of the test below from another tutorial but it still fails with 'Error: No pending request to flush'

the test:

describe('currencyCtrlr: getCurrencies', function() {
    var scope, CurrencyConversion, UpdateMiniBasket, whiskyList, $httpBackend, $rootScope, createController,
        url = 'http://api.exchangeratelab.com/api/current/GBP?apikey=F06383D65BCBFF52629D059B7D3EEB7D&callback=JSON_CALLBACK';

    beforeEach(module('whiskyControllers'));

    beforeEach(function () {
        module(function ($provide) {
            $provide.value('CurrencyConversion', CurrencyConversion);
            $provide.value('UpdateMiniBasket', UpdateMiniBasket);
            $provide.value('whiskyList', whiskyList);
        });
    });

    beforeEach(inject(function($injector) {
        //scope = $rootScope.$new();
        $httpBackend = $injector.get('$httpBackend');
        $httpBackend.when('GET', url).respond({}, {});

        $rootScope = $injector.get('$rootScope');
        var $controller = $injector.get('$controller');

        createController = function() {
            return $controller('currencyCtrlr', {'$scope' : $rootScope });
        };
    }));

    it('should make an ajax call to http://api.exchangeratelab.com', function() {
        $httpBackend.expectGET(url);
        var controller = createController();
        $httpBackend.flush();
    });

    afterEach(function() {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

});

Any help will be really appreciated

Upvotes: 0

Views: 103

Answers (1)

Davin Tryon
Davin Tryon

Reputation: 67296

When you create the controller with createController the getCurrencies method is not called. Therefore, there is no $http calls to flush. Try this instead:

it('should make an ajax call to http://api.exchangeratelab.com', function() {
        $httpBackend.expectGET(url);
        var controller = createController();
        $rootScope.getCurrencies();
        $httpBackend.flush();
});

Although, the above code will probably then error on the e.preventDefault(). So, you need to pass something that will satisfy that, or delete it (because it really shouldn't be needed anyway).

Another thing that is slightly odd is that you are using $rootScope as $scope. It might be better to create a local scope property and create a new scope with:

scope = $rootScope.$new();

And then use that to call scoped methods.

Upvotes: 1

Related Questions