سؤال

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!

هل كانت مفيدة؟

المحلول

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top