I have a directive here I'm trying to write a unit test for - first time doing this type of thing. I'm not sure how to go about it. Here's the directive code and HTML :
app.directive('passwordMatch', [function () {
return {
restrict: 'A',
scope:true,
require: 'ngModel',
link: function (scope, elem, attrs, control) {
var checker = function () {
var e1 = scope.$eval(attrs.ngModel);
var e2 = scope.$eval(attrs.passwordMatch);
if(e2!=null)
return e1 == e2;
};
scope.$watch(checker, function (n) {
control.$setValidity("passwordNoMatch", n);
});
}
};
}]);
<form name="signupForm">
<div class="form-group">
<div class="col-sm-7">
<span class="block input-icon input-icon-right">
<input type="password" class="register" name="password" placeholder="Password" ng-model="signup.password" required/>
</span>
</div>
</div>
<div class="form-group">
<div class="col-sm-7">
<span class="block input-icon input-icon-right">
<input type="password" class="register" name="password2" placeholder="Confirm Password" ng-model="signup.password2" password-match="signup.password" required/>
<small class="errorMessage" data-ng-show="signupForm.password2.$dirty && signupForm.password2.$error.passwordNoMatch && !signupForm.password2.$error.required"> Password do not match.</small>
</span>
</div>
</div>
</form>
And here's what I'm trying for a test. So for, it is giving me an error reading TypeError: 'undefined' is not an object (evaluating 'scope.signup.password = '123'')
describe('passwordMatch Directive - ', function() {
var scope, $compile, $window, element;
beforeEach(function() {
module('myApp');
inject(function(_$compile_, _$rootScope_, _$window_) {
$compile = _$compile_;
scope = _$rootScope_.$new();
$window = _$window_;
})
})
it('should indicate invalid when the passwords do not match.', function() {
scope.signup.password = '123';
scope.signup.password2 = '1234';
element = $compile(angular.element('<input type="password" class="register" name="password" placeholder="Password" ng-model="signup.password" required/> <input type="password" class="register" name="password2" placeholder="Confirm Password" ng-model="signup.password2" password-match="signup.password" required/>'))(scope);
scope.$apply();
console.debug('element html - ' + element.html());
expect(element.html().indexOf('ng-invalid')).toBeGreaterThan(0);
});
it('should indicate valid when the passwords do not match.', function() {
scope.signup.password = '123';
scope.signup.password2 = '123';
element = $compile(angular.element('<input type="password" class="register" name="password" placeholder="Password" ng-model="signup.password" required/> <input type="password" class="register" name="password2" placeholder="Confirm Password" ng-model="signup.password2" password-match="signup.password" required/>'))(scope);
scope.$apply();
console.debug('element html - ' + element.html());
expect(element.html().indexOf('ng-valid')).toBeGreaterThan(0);
});
});
Some help would be greatly appreciated
EDIT: I just noticed when commenting out scope.signup.password = '123'
and such, the debug statement does not return anything - just DEBUG: 'element html - '
, so element.html() is not doing anything?
I've not done testing for a while but have you tried defining the scope.signup object first, perhaps in your beforeEach block. So, something like,
describe('passwordMatch Directive - ', function() {
var scope, $compile, $window, element, elm;
beforeEach(function() {
module('myApp');
inject(function(_$compile_, _$rootScope_, _$window_) {
$compile = _$compile_;
scope = _$rootScope_.$new();
$window = _$window_;
});
// define scope.signup as an empty object literal to which
// you can add properties later
scope.signup = {};
// don't think you meant to have this so commenting it out
//elm
})
it('should indicate invalid when the passwords do not match.', function() {
scope.signup.password = '123';
scope.signup.password2 = '1234';
element = $compile(angular.element('<input type="password" class="register" name="password" placeholder="Password" ng-model="signup.password" required/> <input type="password" class="register" name="password2" placeholder="Confirm Password" ng-model="signup.password2" password-match="signup.password" required/>'))(scope);
scope.$apply();
console.debug('element html - ' + element.html());
expect(element.html().indexOf('ng-invalid')).toBeGreaterThan(0);
});
// etc...
});
EDIT
I think you need to have your inputs inside a form. Try this...
describe('passwordMatch Directive - ', function() {
var scope, $compile, $window, element, html;
beforeEach(function() {
module('myApp');
inject(function(_$compile_, _$rootScope_, _$window_) {
$compile = _$compile_;
scope = _$rootScope_.$new();
$window = _$window_;
});
scope.signup = {};
// inputs need to be within a form for you directive to work
html = '<form name="signupForm">' +
'<input type="password" class="register" name="password" placeholder="Password" ng-model="signup.password" required/>' +
'<input type="password" class="register" name="password2" placeholder="Confirm Password" ng-model="signup.password2" password-match="signup.password" required/>' +
'</form>';
});
it('should indicate invalid when the passwords do not match.', function() {
scope.signup.password = '123';
scope.signup.password2 = '1234';
element = $compile(angular.element(html))(scope);
scope.$apply();
console.debug('element html - ' + element.html());
expect(element.html().indexOf('ng-invalid')).toBeGreaterThan(0);
});
it('should indicate valid when the passwords do not match.', function() {
scope.signup.password = '123';
scope.signup.password2 = '123';
element = $compile(angular.element(html))(scope);
scope.$apply();
console.debug('element html - ' + element.html());
expect(element.html().indexOf('ng-valid')).toBeGreaterThan(0);
});
});
EDIT 2
You can access the FormController properties directly from the scope too and make assertions on these properties rather than using element.html()
. Makes it a bit more readable.
it('should indicate invalid when the passwords do not match.', function() {
scope.signup.password = '123';
scope.signup.password2 = '1234';
element = $compile(angular.element(html))(scope);
scope.$apply();
// expect(element.html().indexOf('ng-invalid')).toBeGreaterThan(0);
expect(scope.signupForm.$valid).toBe(false);
expect(scope.signupForm.$invalid).toBe(true);
});
it('should indicate valid when the passwords do not match.', function() {
scope.signup.password = '123';
scope.signup.password2 = '123';
element = $compile(angular.element(html))(scope);
scope.$apply();
//expect(element.html().indexOf('ng-valid')).toBeGreaterThan(0);
expect(scope.signupForm.$valid).toBe(true);
expect(scope.signupForm.$invalid).toBe(false);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With