Creating a Jasmine-tested jQuery Plugin Using Node/Travis CI

These days it’s well-accepted that code should be well-tested and documented and [of course] being algorithmically sound and unobtrusive. To demonstrate this, I created a quick and simple jQuery plugin using Jasmine to test. The following post provides a guide from start to finish: plugin boilerplate, tests in Jasmine using node, tests running on Travis CI, and plugin created on the jQuery plugin site.

Boilerplate

To preface, I’ll first begin by explaining the idea behind a jQuery plugin. When you create a jQuery plugin, all you are doing is extending a jQuery object with a method of your own. This is normally done through javascript via prototypical inheritance. Thus when a browser loads your plugin, a jQuery object will have access to your defined method. Afterwards, you can then call your plugin’s method on the object which will run its initialize method to perform the its initialization logic. Fortunately, there exists jQuery Boilerplate that dramatically simplifies this. You can use this as an initial step to creating your jQuery plugin. The code is very concise and has detailed comments to further explain what goes into creating a jQuery plugin.

Testing

If you have node and npm installed, you will need a few more packages:

  • jquery
  • jsdom: Allows you to create a window object in your tests
  • jasmine-node
  • jasmine-jquery

You can install these using npm install <package name>.

Once these are installed, you will need to create a file with extension .spec.js. This will allow jasmine to read and run your test. Inside this file you will want to have setup code that will allow your test to run using the minimum requirements, such as having the following available: window and document object, jquery, jasmine, and lastly your source code as shown below.

snippet: jquery.simple-infinite-scroll.spec.js jQuery Simple Infinite Scroll
1
2
3
4
5
6
7
jQuery = require('jquery');
$ = jQuery;
window = require('jsdom').jsdom().createWindow();
document = window.document;
jqueryJasmine = require('jasmine-jquery');

require('../../src/jquery.simple-infinite-scroll');

From there, you can begin to write tests for your plugin. Jasmine provides a very similar interface to its ruby counterpart. You can create test suites using describe and specs using it. These are just functions in javascript. For example, the describe() function takes two arguments: a string and a function. The string is what your suite would be named and the function is what would be called to run your test logic. This same idea applies to the it() function. As an example, see below:

snippet: jquery.simple-infinite-scroll.spec.js jQuery Simple Infinite Scroll
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
describe('jQuery Simple Infinite Scroll', function () {
  beforeEach(function () {
    setFixtures(
      '<div id="jasmine-fixtures">' +
        '<div class="fixture" style="height: 2000px; border: 2px solid #000;">
</div>' +
      '</div>'
    );

    spyOn($.prototype, 'height').andCallFake(function () {
      var original = $.prototype.height;
      if (this[0] === window) {
        return 1;
      } else if (this[0] === document) {
        return 0
      } else {
        return original.apply(this, arguments);
      }
    });

    spyOn($, 'ajax').andCallFake(function (params) {
      params.success('success');
    });
  });

  it('should be able to be instantiated onto a DOM element', function () {
    expect($(window).simpleInfiniteScroll()).toBeTruthy();
    expect($('#jasmine-fixtures').simpleInfiniteScroll()).toBeTruthy();
  });

  it('should be able to override its default options', function () {
    expect(
      $(window).simpleInfiniteScroll({
        offset: 1,
        ajaxOptions: {
          url: '/foo/1/bar',
          async: true,
          type: 'POST',
          dataType: 'json',
          data: {},
          beforeSend: function (xhr) {
            xhr.setRequestHeader('X-CSRF-Token',
            $('meta[name="csrf-token"]').attr('content'));
          },
        },
        callback: function (data, textStatus, jqXHR) { console.log('foo'); }
      })
    ).toBeTruthy();
  });

  it('should send an ajax request once scrolled near the bottom of the page',
function () {
    $(window).simpleInfiniteScroll();
    $(window).scroll();
    expect($.ajax).toHaveBeenCalled();
  });
});

In the test suite, you will see I used a beforeEach() function to set up a simple fixture and two spies. This function will run before each test case.

On line 3, I used setFixtures() which takes one argument, a string. If a fixture is sufficiently large, it wouldn’t be feasible to type out an entire HTML file. For this, you can use the alternative loadFixtures() function.

The other components are spies. I created two spies, one for detecting a mouse wheel scroll inside a window and one for detecting an ajax call. These spies serve as hooks into your test cases. The idea of spies is to define a hook for some action. Optionally, once an action is triggered, you can write in extra logic, such as on lines 21-24 where an ajax call will send back a fake response.

To run your tests, you can call jasmine-node <file_name>.spec.js. Once you are complete with your code and tests, you can begin the publishing process.

Travis CI

Travis CI is a continuous integration solution for open source code. First you have to establish a hook into Github. Once in place, Travis CI will run your test suite after every commit you make to the repo.

You will need two configuration files: _travis.yml and package.json.

In order to alleviate any Travis CI configuration issues, you can use the following as a basis for your own configuration.

.travis.yml.travis.yml
1
2
3
4
5
6
7
8
9
10
language: node_js
node_js:
  - "0.9"
  - "0.8"
branches:
  only:
  - master
before_script:
  - "npm i -g jasmine-node"
  - "npm i -g jasmine-jquery"
package.jsonpackage.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "name": "simple-infinite-scroll",
  "version": "0.1.1",
  "description": "A simple jQuery plugin to be used for
handling pagination on vertical scroll",
  "repository": {
    "type": "git",
    "url": "https://github.com/jnaru/simple-infinite-scroll.git"
  },
  "author": "Jeff Chao <jeffchao@me.com>",
  "maintainers": "Jeff Chao <jeffchao@me.com>",
  "licenses": ["MIT"],
  "dependencies": {
    "jasmine-node": ">=1.3.1",
    "jquery": ">=1.8.3",
    "jasmine-jquery": ">=1.3.3"
  },
  "scripts": {
    "test": "jasmine-node spec"
  }
}

Travis CI provides a detailed view of your open sourced code. See below for an example.

Travis CI build example

Now that Travis CI is in place, you can publish your plugin to the jQuery plugin site.

Publishing your jQuery plugin

jQuery requires the package.json from above to work properly. The way plugins get published is by establishing a hook into your Github repo. The way it works is by tagging your repo. When you tag a particular branch, jQuery will be notified and consequently update your plugin’s information on the site. This is where the package.json comes into play. The information provided from the json is used to populate information pertaining to your plugin. One thing to note is the version in your package.json. Either you manage this yourself or use some version manager, you need to ensure the versions are consistent and accurate otherwise you will have issues publishing your plugin.

To summarize, everytime you commit to your Github repo, Travis CI will run your test suite. Everytime you tag your repo, jQuery will be notified of any changes.