How to Start Doing TDD for jQuery Plugin.

I’m a big fan of TDD. I get nervous every time when I put some code it without having tests. I’m developing a simple jQuery plugin and I think hey we can TDD this.

What is it?

The plugin is really simple. It turns ul tag to be taggable field. It’s similar to tag-it but with a lot less functionalities and doesn’t depend on jquery-ui

What you need

I decided to use Karma because I’m going to test a lot of behaviours and Karma seems like a good fit as it run on real browser. Here’s how I setup my project.

I chose jasmine-jquery because it’s easier to create some element to test and it’s easy to setup.

This is my gulpfile.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var gulp = require('gulp');
var karma = require('gulp-karma');

var testFiles = [
  'tests/vendors/jquery-1.11.3.min.js',
  'tests/vendors/jasmine-jquery.js',
  'src/**/*.js',
  'tests/spec/**/*.js'
];
/**
 * Run test once and exit
 */
gulp.task('test', function (done) {
  return gulp.src(testFiles)
    .pipe(karma({
      configFile: 'karma.conf.js',
      action: 'run'
    }))
  .on('error', function(err) {
    // Make sure failed tests cause gulp to exit non-zero 
    throw err;
  });
});

gulp.task('default', function() {
  gulp.src(testFiles)
    .pipe(karma({
      configFile: 'karma.conf.js',
      action: 'watch'
    }));
});

This is my karma.conf.js

1
2
3
4
5
6
module.exports = function(config) {
  config.set({
    browsers: ['PhantomJS'],
    frameworks: ['jasmine']
  });
};

Here’s my first test

1
2
3
4
5
6
7
8
9
10
11
12
13
describe('Taggify', function() {
  var fixture;
  beforeEach(function() {
    fixture = setFixtures('<ul id="tag"></ul>');
    jQuery('#tag').taggify();
  });

  it('should initialize text box', function() {
    var input = fixture.find('input');
    expect(input.length > 0).toBeTruthy();
  });

});

You will see that the test failed now we implement some code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(function($) {
  $.fn.taggify = function(options) {
    create(this);
    return this;
  };

  function create($theElement) {
    var $input = $('<input class="tag-input"></input>')
      .attr('type', 'text')
      .attr('autocomplete', 'off')
      .wrap('<li></li>');

    $theElement.append($input.parent());
  }
})(jQuery);

Now the test passed.

Now let’s add some event so when you hit enter the tag is added. So, I added one more test

1
2
3
4
5
6
7
8
9
10
11
  it('should add a tag', function() {
    var input = fixture.find('input');
    input.val('tag');
    input.trigger(jQuery.Event('keyup', { keyCode: 13 }));

    var tags = fixture.find('.tag-label');
    var tag = jQuery(tags[0]);

    expect(tag.html()).toBe('tag');
    expect(tags.length > 0).toBeTruthy();
  });

Now the test failed.

I’ll fix the test by doing this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
(function($) {
  $.fn.taggify = function(options) {
    create(this);
    return this;
  };

  function create($theElement) {
    var $input = $('<input class="tag-input"></input>')
      .attr('type', 'text')
      .attr('autocomplete', 'off')
      .wrap('<li></li>');

    $input.on('keyup', function(e) {
      if (e.keyCode === 13) {
        var tagText = $input.val();

        var $span = $('<span class="tag-label"></span>');

        $span.text(tagText).wrap('<li class="tag-choice"></li>');
        $theElement.prepend($span.parent());
        $input.val('');
      }
    });

    $theElement.append($input.parent());
  }
})(jQuery);

Now I want to add some negative test case.

1
2
3
4
5
6
7
  it('should not add a tag', function() {
    var input = fixture.find('input');
    input.trigger(jQuery.Event('keyup', { keyCode: 13 }));
    var tags = fixture.find('.tag-label');

    expect(tags.length > 0).toBeFalsy();
  });

Oops the test failed, looks like I missed something

I will fix the test by

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(function($) {
  $.fn.taggify = function(options) {
    create(this);
    return this;
  };

  function create($theElement) {
    var $input = $('<input class="tag-input"></input>')
      .attr('type', 'text')
      .attr('autocomplete', 'off')
      .wrap('<li></li>');

    $input.on('keyup', function(e) {
      if (e.keyCode === 13) {
        var tagText = $input.val();
        if(tagText !== '') {
          var $span = $('<span class="tag-label"></span>');

          $span.text(tagText).wrap('<li class="tag-choice"></li>');
          $theElement.prepend($span.parent());
          $input.val('');
        }
      }
    });

    $theElement.append($input.parent());
  }
})(jQuery);

That’s it. I hope you enjoy and love TDD more. And here’s the github repo

Jul 9th, 2015

Comments