BIOS
BIOS

Reputation: 1695

Unit testing Javascript that involves the DOM

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

Answers (3)

Alexei Levenkov
Alexei Levenkov

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

Jani Hartikainen
Jani Hartikainen

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

Joseph
Joseph

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

Related Questions