0

I am trying to test the some of the validation for a form I have in a registration view. I have the view file created which contains a form. Now I need to know how I can access this form from inside a unit test so that I can verify the $setValidity is working as expected.

Here's the code I am trying to test:

angular
    .module('enigma.registration', ['ngMessages'])
    .controller('Registration', Registration);

Registration.$inject = ['$state', 'authFactory'];

function Registration($state, authFactory) {
    var reg = this;

    reg.alreadyRegistered = alreadyRegistered;
    reg.error = '';

    function alreadyRegistered() {
        if(reg.regForm.email.$valid){
            authFactory.doesUserExist(reg.user)
                .then(function(response){
                    if(response.data.message === 'user exists') {
                        reg.regForm.email.$setValidity('userExists', false); // I am missing coverage of this line.
                    } else {
                        reg.regForm.email.$setValidity('userExists', true); // I am missing coverage of this line.
                    }
                })
                .catch(function(err){
                    reg.error = err;
                });
        } else { // Input is invalid for reasons other than existing email, do not delete ~ EFarley 9/23/15
            reg.regForm.email.$setValidity('userExists', true); // Remove userExists validation error.
        }
    };    
}

I have tried to unit test this but no matter what I do I can't access the regForm.email.$error property from my unit tests.

Lastly here's how I wrote my unit test:

describe('Registration Controller Tests', function() {
    var $controller, $scope, defer, doesUserExistSpy, authFactory, Registration, $httpBackend, authReqHandler, loginReqHandler, userReqHandler, $state, goSpy, setValiditySpy;

    beforeEach(module('enigma'));

    beforeEach(inject(function (_$controller_, _$rootScope_, $q, $injector) {
        $controller = _$controller_;
        $scope = _$rootScope_;
        defer = $q.defer();

        // Create spies
        doesUserExistSpy = jasmine.createSpy('doesUserExist').and.returnValue(defer.promise);

        authFactory = {
            doesUserExist: doesUserExistSpy
        };   

        Registration = $controller('Registration', {
            $scope: $scope,
            authFactory: authFactory,
            $state: $state
        });
    });

    describe('check email field validity', function () {
        var template, element, regForm;

        beforeEach(inject(function ($templateCache, $compile) {
            template = $templateCache.get('../public/modules/registration/registration.html');
            element = angular.element(template);
            $compile(element)($scope);
            regForm = $scope.regForm;
        }));

        it('should set regForm.email.$error.userExists to true if /doesUserExist returns "user exists"', function () {
            $httpBackend.whenPOST('/doesUserExist').respond('user exists');
            Registration.alreadyRegistered;
            $scope.$digest();
            expect(regForm.email.$error.userExists).toEqual(true);
        });
    });
});

However template always equals undefined, which causes element to be undefined and lastly regForm to be undefined. Because everything is undefined I'm unable to access the $error property of the email field. How do I access the form in my test?

efarley
  • 8,371
  • 12
  • 42
  • 65
  • reg.error is only defined in the catch block. Does adding reg.error at top make a difference? Also in Karma you are looking for $error but the source is error. Copy/paste error? – James Oct 14 '15 at 19:33
  • reg.error is a controller variable containing a plain text error message displayed in the view. regForm.email.$error is the error property of the form used by angular validation, such as required or email. – efarley Oct 14 '15 at 19:37
  • Does this answer help? http://stackoverflow.com/a/22772504/4004512 – James Oct 14 '15 at 19:43
  • No they are manually typing the html for their test not using an existing view. I know how to do it by typing the html out for the element in the test, but that doesn't make sense to recreate views I already created. – efarley Oct 14 '15 at 19:47
  • Hope you find your answer. When testing directives I use angular to compile the dom for me. ` beforeEach(inject(function ($compile, $rootScope) { var html = '
    '; $scope = $rootScope; compiledElem = $compile(html)($scope); controllerObj = compiledElem.controller('controllerName'); })); `
    – James Oct 14 '15 at 19:55
  • Thanks, I also do that in one of my directives where I just needed a couple generic fields. In this case it seems like it would be best to load the actual view, but maybe the correct way to do this is to recreate the relevant parts of the view in the test. – efarley Oct 14 '15 at 20:32

0 Answers0