Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing angular/Ionic project

I have a very simple controller that looks like this.

timeInOut.controller('timeInOutController', function($scope, $filter, $ionicScrollDelegate){

    ... 

});

Whenever I try to create a unit test for it like so...

(function() {
'use strict';

    var scope, controller, filter;

    describe('timeInOutController', function () {

        beforeEach(module('common.directives.kmDateToday'));

        beforeEach(inject(function ($rootScope, $controller, $filter) {
            scope = $rootScope.$new();
            filter = $filter;
            controller = $controller('timeInOutController', {
                $scope: scope
            });
        }));

        describe('#date setting', function(){

            ...

        });
    });
})();

I get the error:

[$injector:unpr] Unknown provider: $ionicScrollDelegateProvider <- $ionicScrollDelegate

Obviously in my example here I'm not trying to inject the $ionicScrollDelegate into the test, that's just because I've tried it any number of ways with no success and don't know which failed attempt to include.

Also in my karma.conf.js file I am including the ionic.bundle.js and angular-mocks.js libraries/files.

I can successfully unit test anything that doesn't use anything $ionic in it, so I know my testing framework is set up correctly, the issue is injecting anything ionic related.

like image 883
Hoser Avatar asked Oct 28 '14 15:10

Hoser


2 Answers

You need to pass in all the parameters if you're going to instantiate your controller via angular. By adding the parameters you are telling angular that any time you create one of these controllers I need these things too because I am dependent upon them.

So my suggestion is to mock up some representation of these dependencies and inject them in when you are creating the controller. They do not have to be (and should not be) the actual services for your unit tests. Jasmine gives you the ability to create spy objects that you can inject so you can verify the the behavior of this unit.

(function() {
'use strict';

    var scope, controller, filter, ionicScrollDelegate;

    describe('timeInOutController', function () {

        beforeEach(module('common.directives.kmDateToday'));

        beforeEach(inject(function ($rootScope, $controller, $filter) {
            scope = $rootScope.$new();
            filter = $filter;

            // func1 and func2 are functions that will be created as spies on ionicScrollDelegate
            ionicScrollDelegate = jasmine.createSpyObj('ionicScrollDelegate', ['func1', 'func2']
            controller = $controller('timeInOutController', {
                $scope: scope,
                $filter: filter,
                $ionicScrollDelegate: ionicScrollDelegate
            });
        }));

        describe('#date setting', function(){

            ...

        });
    });
})();

You can find more about spies via jasmine's documentation

like image 53
Brocco Avatar answered Sep 30 '22 19:09

Brocco


You need to create mock objects for all dependencies your controller is using.

Take this controller as an example:

angular.module('app.module', [])
    .controller('Ctrl', function($scope, $ionicLoading) {
        $ionicLoading.show();
    });

Here you are using the $ionicLoading service, so if you want to test this controller, you have to mock that object specifying the methods you're using in the controller:

describe('Test', function() {
     // Mocks
     var $scope, ionicLoadingMock;
     var ctrl;
     beforeEach(module('app.module'));
     beforeEach(function() {
         // Create $ionicLoading mock with `show` method
         ionicLoadingMock = jasmine.createSpyObj('ionicLoading', ['show']);
         inject(function($rootScope, $controller) {
             $scope = $rootScope.$new();
             ctrl = $controller('Ctrl', {
                 $scope: $scope,
                 $ionicLoading: ionicLoadingMock
             });
         });
     });
     // Your test goes here
     it('should init controller for testing', function() {
         expect(true).toBe(true);
     });
});
like image 43
amb Avatar answered Sep 30 '22 20:09

amb