0

I have a controller that is calling a service. I want to write my unit tests such that I get coverage on the success and error functions of the then function.

maApp.controller('editEmailAndPasswordController', 
                 ["$scope", "emailAndPasswordService",
    function editEmailAndPasswordController($scope, emailAndPasswordService) {
        $scope.EmailId = '[email protected]';
        $scope.CurrentPassword = '';
        $scope.Success = false;

        $scope.save = function () {
            var request = {
                currentPassword: $scope.CurrentPassword,
                newEmailId: $scope.EmailId
            };
            emailAndPasswordService.save(request).then(function (data) {
                $scope.Success = true;
            }, function (data, status, header, config) {
                $scope.Success = false;
            });
        };
    }]);

This is what I have got so for. I want another test for the fail condition as well, but not sure how to set up the mock service.

describe('Controllers', function () {
    var $scope, ctrl, controller, svc, def;
    describe('editEmailAndPasswordController', function () {

        beforeEach(function() {
            module('maApp');
        });

        beforeEach(inject(function ($controller, $rootScope, $q) {
            ctrl = $controller;
            svc = {
                save: function () {
                    def = $q.defer();
                    return def.promise;
                }
            };
            spyOn(svc, 'save').andCallThrough();
            $scope = $rootScope.$new();
            controller = ctrl('editEmailAndPasswordController', { $scope: $scope, emailAndPasswordService: svc });
        }));

        it('should set ShowEdit as false upon save', function () {
            $scope.ShowEdit = true;
            $scope.EmailId = 'newEmail';
            $scope.CurrentPassword = 'asdf1';

            $scope.save();
            expect($scope.EmailId).toBe('[email protected]');
            expect($scope.Success).toBe(true);
        });
    });
});

2 Answers 2

3

You have some real problems with this code.

  1. Don't call ".andCallThrough()"- that way your test depends on the implementaton of the service and means your controller is not isolated. The main idea is to create unit tests.

    svc = {save: jasmine.createSpy()};

    svc.save.andReturn(...);

  2. You can't assert against expect($scope.EmailId).toBe('[email protected]'); because you change the value in the code to $scope.EmailId = 'newEmail';

  3. you can create 2 private methods for readability

    function success(value) { var defer = q.defer(); defer.resolve(value); return defer.promise; }

    function failure(value){ var defer = q.defer(); defer.reject(value); return defer.promise; }

Thus in the first test you can call

svc.save.andReturn(success());

$scope.$digest()

expect($scope.Success).toBeTruthy();

And in the other test you will have the same but:

svc.save.andReturn(failure());

$scope.$digest()

expect($scope.Success).toBeFalsy();

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

2 Comments

In your success function you are calling reject, just changed that on my side and it worked like a charm.
Ah my mistake sorry , but you got the idea and glad that i helped ;)
1

In one case, you want the promise to be successful, so you want to resolve the deferred:

$scope.save();

def.resolve('whatever');
$scope.$apply();

expect($scope.Success).toBe(true);
...

In the other case, you want the promise to be a failure, so uou want to reject the deferred:

$scope.save();

def.reject('whatever');
$scope.$apply();

expect($scope.Success).toBe(false);
...

This is explained in the documentation.

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.