5

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.

2 Answers 2

6

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

Sign up to request clarification or add additional context in comments.

4 Comments

I sorta understand what you mean but do you think you could give a quick code example? Do you mean like a separate folder/file that mocks some of these ionic dependencies and inject them?
This worked, only thing I had to change was createSpyObject(... to createSpy(..., not sure if createSpyObject is an actual function. Thank you so much!
I added that without reviewing the documentation, but the method I was referring to is createSpyObj, it is helpful for creating multiple spies on an object.
Good info. Thank you again!
3

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);
     });
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.