Question

I am very new to testing in Javascript and am currenly trying to test a controller function. The function calls a service method which retrieves data from a web sql db.

This is a part of my controller function (it contains 2 callbacks, one for success and another for error):

    $scope.getLocations = function () {
        LocationDbService.getAll(
            //Success
            function (tx, results) {

                $scope.numberOfLocations = results.rows.length;
                ...
            },
            //Error
            function () {
                console.log("Error");
            });
    }

The test:

it('we should be able to retrieve all stored locations',
    function () {
        expect(scope.numberOfLocations).toBeUndefined();
        scope.getLocations();
        expect(scope.numberOfLocations).toBeDefined();
    });

beforeEach test:

var ctrl, scope, location, locationDbService;
// inject the $controller and $rootScope services
// in the beforeEach block
beforeEach(inject(function ($controller, $rootScope, $location, LocationDbService) {
    // Create a new scope that's a child of the $rootScope
    scope = $rootScope.$new();
    // Create the controller
    ctrl = $controller('LocationsCtrl', {
        $scope: scope
    });
    location = $location;
    locationDbService = LocationDbService;
}));

Controller header:

.controller('LocationsCtrl', function ($scope, $location, LocationDbService) {

When I run the application in the browser (or on my smartphone, its a hybrid app) everything works but when I run the test I get the following:

Test failure

Does somebody know why the scoped variable is still undefined? Thanks in advance!

Était-ce utile?

La solution

When instantiating your controller, you should also inject any other services it needs.

AngularJS has a cool trick btw where you can use underscores in names:

  beforeEach(inject(function ($controller, $rootScope, _$location_, _LocationDbService_) {
        // Create a new scope that's a child of the $rootScope
        scope = $rootScope.$new();
        // Create the controller
        ctrl = $controller('LocationsCtrl', {
            $scope: scope,
            $location : _$location_,
            LocationDbService : _LocationDbService_
        });
        location = _$location_; //thx to the underscores you could use '$location' as name instead of 'location'
        locationDbService = _LocationDbService_;
    }));

Next you should mock the service call:

it('should be able to retrieve all stored locations',
    function () {
        spyOn(locationDbService , 'getAll').andCallFake(function (success, fail) {
             var results = {};
             results.rows = new Array(5);
             success(null, results);
        });
        expect(scope.numberOfLocations).toBeUndefined();
        scope.getLocations();
        expect(scope.numberOfLocations).toBe(5);
    });

The service should have tests of its own.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top