Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to mock $state.params in jasmine unit testing

I have the following controller EditMeetingCtrl.js

(function() {
    'use strict';

    angular
        .module('myApp')
        .controller('EditMeetingCtrl', EditMeetingCtrl);

    EditMeetingCtrl.$inject = ['$rootScope', '$scope', '$state', '$http', '$translate',
        'meetingService', 'companyService', 'notificationService', 'meeting'];

function EditMeetingCtrl($rootScope, $scope, $state, $http, $translate, meetingService, companyService, notificationService, meeting) {
        $scope.meeting = meeting;

        $scope.companyId = $state.params.companyId;
        $scope.save = save;


        function save() {
            $scope.buttonDisable = true;
            meetingService.saveMeeting($state.params.companyId, $state.params.meetingId, $scope.meeting)
                .success(function(meetingId) {
                   //more code
                });
        }


}
})();

EditMeetingCtrlSpec.js test case

describe('in EditMeetingCtrl', function () {

    var companyService , meetingService ;

    meetingId = 123321 ;                      
    companyId = 456654 ;
    meetingObj = {} ;

    var fakeHttpPromise = {
                            success: function() {}
                          };

    beforeEach(angular.mock.module('myApp'));

    beforeEach(angular.mock.inject(function (_$httpBackend_, _companyService_ , _meetingService_) {
        $httpBackend = _$httpBackend_;
        companyService = _companyService_;
        meetingService = _meetingService_ ;
    }));

    describe('EditMeetingCtrl.save()', function () {
        var $rootScope, scope, $controller , $q  ;

        beforeEach(inject(function ($rootScope, $controller , _meetingService_ ) {
            scope = $rootScope.$new();
            createController = function() {
                return $controller('EditMeetingCtrl', {
                $scope: scope,
                meeting : {} ,
                meetingService : _meetingService_
                }); 
            };
            var controller = new createController();
        }));

        it("should save the meeting object", function() {
            spyOn(meetingService, 'saveMeeting').and.returnValue(fakeHttpPromise);
            scope.save();
            expect(meetingService.saveMeeting).toHaveBeenCalledWith( meetingId , companyId , meetingObj);
        });

    });

});

When try to run the below test casse EditMeetingCtrlSpec.js i got the following test failure

PhantomJS 1.9.8 (Windows 8) EditMeetingCtrl Spying --> EditMeetingCtrl.save() should save the meeting FAILED
        Expected spy saveMeeting to have been called with [ 123321, 456654, Object({  }) ] but actual calls were [ undef
ined, undefined, Object({  }) ].

So the way understand my this problem , the service call for save() method contains $state.params.companyId, $state.params.meetingId parameters and it sends an undefined values when the service call get invoked . therefore i need to mock the the $state.params . Not sure how to do it .can anyone point me in the right direction ?

EDIT after Michael Radionov Answer

describe('EditMeetingCtrl.save()', function () {
        var $rootScope, scope, $controller , $q  , $state ;

        beforeEach(inject(function ($rootScope, $controller , $state , _meetingService_ ) {
            scope = $rootScope.$new();
            createController = function() {
                return $controller('EditMeetingCtrl', {
                $scope: scope,
                meeting : {} ,
                meetingService : _meetingService_
                }); 
            };
            var controller = new createController();
        }));

        it("should save the meeting", function() {
            $state.params = { companyId: 123, meetingId: 567 };
            spyOn(meetingService, 'saveMeeting').and.returnValue(fakeHttpPromise);
            scope.save();
            //expect(meetingService.saveMeeting).toHaveBeenCalledWith( meetingId , companyId , meetingObj);
        });

    });

I have done the above, but i get the following error saying $state is not defined .

Firefox 38.0.0 (Windows 8.1) In EditMeetingCtrl EditMeetingCtrl.save() should save the meeting FAILED
        TypeError: $state is undefined in C:/Users/sal/Documents/myApp/test/meeting/EditMe
etingCtrlSpec.js (line 80)

I assumed this happened because i did not do this -> $state : state in the inject method, so i tried doing that too but got the same error . what am i missing here ?

like image 351
Malik Avatar asked Jun 10 '15 05:06

Malik


People also ask

How do I test a mock method with parameters?

The only caveat is you have to set an expectation that your mock get’s called, otherwise if it never gets executed the test will also never fail. 1) Set up the spy on the method for which you want to test the params. 2) Set up the expectation to compare a param to an expected value.

How do you test if a method has the correct params?

1) Set up the spy on the method for which you want to test the params. 2) Set up the expectation to compare a param to an expected value. 3) Call something that should call the method under test with the correct params. 4) Set up an expecatation that makes sure the method under test get’s actually called.

Can I mock a promise in Jasmine?

It’s about an occasional need to mock a promise and perhaps it’s callback params in Jasmine unit-tests and this is a simple example of how it can be done. This is an example of a function you might find in an AngularJS controller (written in TypeScript, but doesn’t matter, it would be almost identical in JS).

How do you mock calls in Jasmine?

Jasmine is a simple, BDD -style JavaScript testing framework, but to benefit from the full power out of the framework, you need to know how to mock calls the Jasmine way. Jasmine uses spies to mock asynchronous and synchronous function calls.


1 Answers

You can mock the entire $state provider and then specify exactly what values do you want to be in the params property before calling save:

describe('in EditMeetingCtrl', function () {

    // ...
    beforeEach(angular.mock.module('myApp'));

    beforeEach(angular.mock.module(function ($provide) {

        // mock the entire $state provider
        $provide.provider('$state', function () {
            return {
                $get: function () {
                    return {
                        // by default it will be an empty object
                        params: {}
                    };
                }
            };
        });

    }));

    // ....

    describe('EditMeetingCtrl.save()', function () {

        // inject mocked $state - one that you've provided above

        var $rootScope, scope, $controller, $q, state;
        // ---------------------------------------^^^

        beforeEach(inject(function ($rootScope, $controller, $state, _meetingService) {
            // ------------------------------------------------^^^
            state = $state;
        }));

        // ...

        it("should save the meeting object", function() {

            // provide custom params which will be used in a call
            state.params = { companyId: 123, meetingId: 567 };

            spyOn(meetingService, 'saveMeeting').and.returnValue(fakeHttpPromise);
            scope.save();
            expect(meetingService.saveMeeting).toHaveBeenCalledWith( meetingId , companyId , meetingObj);
        });
    });

    // ...

});
like image 144
Michael Radionov Avatar answered Sep 19 '22 08:09

Michael Radionov