Reputation: 1695
How do you go about unit testing javascript that uses and modifies the DOM?
I'll give an easy example. A form validator that checks for blank text fields, written in javascript and that uses JQuery.
function Validator() {
this.isBlank = function(id) {
if ($(id).val() == '') {
return true;
} else {
return false;
}
};
this.validate = function(inputs) {
var errors = false;
for (var field in inputs) {
if (this.isBlank(inputs[field])) {
errors = true;
break;
}
}
return errors;
};
}
Usage:
var validator = new Validator();
var fields = { field_1 : '#username', field_2 : '#email' };
if (!validator.validate(fields)) {
console.log('validation failed');
} else {
console.log('validation passed');
}
What is the best practice for attempting to unit test something like this?
Upvotes: 33
Views: 15947
Reputation: 100527
In unlikely case when most of your JavaScript code contains logic and rely on small amount of jQuery code (or live DOM elements) you can refactor code to make replacing access to DOM/usage of jQuery easy and write test with mock implementations:
function Validator(){
this.getElementValue = function(id){return $(id).val();}
this.check_blank = function(id){
if(this.getElementValue(id) == '') // replace direct call to jQuery mock-able call
return false;
else
return true;
}....
}
And in test provide mock implementation:
test("Basic valid field", function() {
var validation = new Validator();
// replace element accessor with mock implementation:
validation.getElementValue = function(id){
equals(id, "#my_field"); // assert that ID is expected one
return "7";
}
var form_fields = {field_1 : '#my_field'};
ok(validation.validate(form_fields), "non-empty field should be valid");
}
Upvotes: 9
Reputation: 43243
Ideally you should split the code. The validation logic does not really require DOM access, so you would put that into its own function, and put the logic that processes the ID into a value that is then validated into another.
By doing this, you can more easily unit test the validation logic, and if necessary do a functional test on the whole thing using some of the tools suggested by Joseph the Dreamer.
Upvotes: 23
Reputation: 119837
You can use Qunit for unit tests involving DOM. If you want it automated, you can use Grunt with grunt-contrib-qunit task which launches your pages in a headless WebKit called PhantomJS.
Upvotes: 10