Question

I am having trouble running a test that uses a mockup for a service call (retrieve a location from the web sql database).

This is the controller:

.controller('LocationDetailCtrl', function ($scope, $stateParams, LocationDbService, ProjectDbService) {

    $scope.getLocation = function () {

        LocationDbService.get($stateParams.locationId,
            //Success
            function (tx, results) {

                console.log(JSON.stringify(results.rows.item(0)));

                if (results.rows.length > 0) {
                    console.log("We are in the if statement");
                    $scope.location = {
                        id: results.rows.item(0).id,
                        name: results.rows.item(0).name,
                        address: results.rows.item(0).address,
                        lat: results.rows.item(0).latitude,
                        lng: results.rows.item(0).longitude,
                        radius: results.rows.item(0).radius
                    }
                    $scope.$apply();
                }
            },
            //Error
            function () {
                console.log("Could not retrieve the location");
            })
    }

Before each test:

var ctrl, scope, locationDbService, projectDbService, stateparams;
// inject the $controller and $rootScope services
// in the beforeEach block
beforeEach(angular.mock.inject(function ($controller, $rootScope, _LocationDbService_, _ProjectDbService_) {
    // Create a new scope that's a child of the $rootScope
    scope = $rootScope.$new();

    stateparams = {locationId: 1}; //mock your stateparams object with your id

    // Create the controller
    ctrl = $controller('LocationDetailCtrl', {
        $scope: scope,
        $stateParams: stateparams,
        LocationDbService: _LocationDbService_,
        ProjectDbService: _ProjectDbService_
    });
    locationDbService = _LocationDbService_;
    projectDbService = _ProjectDbService_;
}));

The test:

 it('a location should be retrieved',
    function () {
        spyOn(locationDbService, 'get').andCallFake(function(success, fail){

            var results = [];
            results.push(
                {
                    "id": 1,
                    "name": "Jeroen",
                    "address": "Kontitch",
                    "latitude": "27.6648274",
                    "longitude": "-81.51575350000002",
                    "radius": 50
                });

            var rs = {
                //rs is a SQLResultSetobject
                insertId: 0,
                rowsAffected: 0,
                rows: {
                    //rows is a SQLResultSetRowListobject
                    length: results.length,
                    item: function(index) {
                        return results[index];
                    }
                }
            };

            success(null, rs);
        });

        expect(scope.location).toBeUndefined();
        scope.getLocation();
        expect(scope.location).toBeDefined();
    });

I get the following test failure:

Number is not a function

Does somebody know why I get this error? Thanks in advance!

Was it helpful?

Solution

I don't believe that you can use angular.mock.inject to mock your own service for you. I have always created an object that has the needed fields/functions on it to mock the service via spies. Inject what you can:

inject(function ($controller, $rootScope)

mock what you can't

stateparams = {locationId: 1};
locationDbService = jasmine.createSpyObj('LocationDbService', ['method1', 'method2']);
projectDbService= jasmine.createSpyObj('ProjectDbService', ['method3', 'method4']);

Then create your controller with these:

ctrl = $controller('LocationDetailCtrl', {
    $scope: scope,
    $stateParams: stateparams,
    LocationDbService: locationDbService ,
    ProjectDbService: projectDbService
});

This way you have full control over what is being injected into your controller to truly isolate it for your unit test.

OTHER TIPS

I've created following mock in the beforeEach:

        locationDbServiceMock = {
        get: function (index,cbsuccess, cberror) {
            var results = [];
            results.push(
                {
                    "id": 1,
                    "name": "Jeroen",
                    "address": "Kontitch",
                    "latitude": "27.6648274",
                    "longitude": "-81.51575350000002",
                    "radius": 50
                });

            var rs = {
                //rs is a SQLResultSetobject
                insertId: 0,
                rowsAffected: 0,
                rows: {
                    //rows is a SQLResultSetRowListobject
                    length: results.length,
                    item: function (index) {
                        return results[index];
                    }
                }
            };

            cbsuccess(null, rs);
        }
    };

I just inject this mocked service into my controller and it works.

I've found what was wrong with my code, I forgot the index parameter:

U can use this:

function (locId, success, fail)

Or my mockup object in the other answer

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top