The jQuery team have made the tough, but inevitable decision to stop supporting IE8 and below as of jQuery v2.0, while maintaining v1.9 as the backwards compatible version for the forseeable future.
In the world of modern, evergreen and mobile browsers, this was a necessary move to ensure jQuery stays relevant. Of course, this split leaves plugin authors with a bit more responsibility.
Where previously we could simply require the most recent version of jQuery, we are now likely to want to support both 1.9.x and 2.x, allowing our plugins to work everywhere from IE6 to the most bleeding edge browsers.
To facilitate this, we’ll run through the creation of a plugin using the popular JavaScript build tool, Grunt. We’ll then configure our unit tests to run automatically across multiple versions of jQuery.
A simple jQuery plugin
Note: If you have an existing plugin that doesn’t use Grunt, I’d suggest running through these steps in a clean directory and porting the resultant code into your project (with some manual tweaks, of course).
Assuming you already have Git and Node.js, we first need Grunt-init and the Grunt command line interface installed globally. Run the following command to ensure you have the latest version:
1
|
|
Note: If you already have an older version of Grunt installed, you’ll need to first remove it with npm uninstall -g grunt
.
We also need to install the ‘grunt-init-jquery’ template into our ’~/.grunt-init’ directory by cloning the repository:
1
|
|
We can now scaffold a new jQuery project:
1 2 3 |
|
Once we’ve responded to all the prompts, we’re left with a basic jQuery plugin with QUnit tests.
Before we continue, we need to install our Node dependencies by running the following command from within our new plugin directory:
1
|
|
We can run our placeholder tests like so:
1 2 3 4 5 6 7 |
|
For the purposes of this tutorial, we’re not terribly interested in the contents of the plugin. Instead, we’ll focus solely on the build and test infrastructure.
Before we make changes to our placeholder project, it’s worth having a closer look at what has been generated.
Inspecting the build
All of the configuration for our Grunt build process sits inside our Gruntfile (Gruntfile.js) in our project directory.
We have ‘qunit’ configuration, which looks for all QUnit files in the ‘test’ directory:
1 2 3 4 5 6 7 |
|
At the end of our Grunt configuration is the definition of our default task:
1 2 |
|
The default task is run when the ‘grunt’ command is executed without any arguments:
1
|
|
Inspecting the test
The QUnit test for our plugin resides in ‘test/plugin.html’. Its default markup looks like 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 |
|
This page is responsible for including jQuery, QUnit (both JavaScript and CSS), our plugin, and any helpers required. It also provides the markup needed for QUnit to generate an HTML report.
You’ll notice, the first script file included is ’../libs/jquery-loader.js’. If we look at the contents of that file, we find this:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
By including this script, we now have the ability to add ‘?jquery=X.X.X’ to the query string, when viewing this page in the browser.
Doing this will cause a hosted version of our specified version of jQuery to be included in the page rather than the default version provided inside our project.
Preparing the build
You might think that we could simply modify the QUnit file matcher in our Gruntfile to add a query string, but this won’t work. Files must exist on the file system, and query strings aren’t part of that vocabulary.
To automatically run our tests with different query strings, we first need to host our test on a local server.
Luckily, Grunt has an officially-supported ‘connect’ task which does the work for us by running a server using Connect.
To install the ‘grunt-contrib-connect’ Grunt plugin, we need to install it, and automatically save it as a development dependency in our ‘package.json’ file:
1
|
|
Before we can use this Grunt plugin, we need to register it with Grunt by adding the following line to our Gruntfile’s ‘loadNpmTasks’:
1
|
|
We can configure our server by adding the following task configuration to our Gruntfile:
1 2 3 4 5 6 7 |
|
If we modify our default task to first include our newly configured ‘connect’ task, this server will start every time the default task is executed, and stopped when the build has completed:
1 2 |
|
Since we want to be able to test our plugin without having to concatenate and minify it, I recommend adding the following ‘test’ task:
1
|
|
We can now lint and test our code from the command line like so:
1
|
|
Configuring the test URLs
So far we have a local Connect server running every time we trigger a build, and we have a ‘test’ task which will run the server before linting our code and running our QUnit tests.
However, you’ll find that we’re still pointing QUnit at the file system. Instead, we want it to point to our new server.
To achieve this, we’ll pass QUnit an array of URLs rather than files:
1 2 3 4 5 6 7 8 9 |
|
Now when we run our tests, we should basically see the same result as before:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
You’ll notice that this time, QUnit is accessing a URL instead of a file. This means that we’re now free to add query strings to our URLs, allowing us to automate testing across multiple versions of jQuery with ease:
1 2 3 4 5 6 7 8 9 10 |
|
Since there will be a lot of repetition in the URLs, let’s clean it up with use of the Array prototype’s ‘map’ method:
1 2 3 4 5 6 7 8 9 |
|
If we run our tests, you’ll see multiple URLs have been loaded, and twice as many assertions have passed:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Making it bulletproof
By default, this setup loads each version directly from the jQuery site. If you’re anything like me, you sometimes develop with little to no internet connectivity, and this limitation would prevent you from running the full suite.
It’s a good idea to add each major supported version of jQuery to your ‘lib/jquery’ directory (with a ‘jquery-x.x.x’ naming convention), and modify ‘libs/jquery-loader.js’ to load these local copies instead:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Testing in the cloud
As always, it’s a great idea to automatically run these tests after every push to GitHub, or on every pull request that is sent to you. To achieve this, we can leverage Travis CI with only a couple of changes to our project.
First add the ‘.travis.yml’ configuration file to your plugin’s base directory:
1 2 3 4 |
|
Then, set the ‘npm test’ script in your ‘package.json’ file to run our new Grunt ‘test’ task:
1 2 3 4 5 6 7 |
|
Finally, follow the official Travis CI guide to create an account, if needed, and activate the GitHub service hook. Once completed, you’ll have the confidence of knowing that the downloadable version of your plugin can’t be broken by mistake.
Keeping it in check
Now that we have a framework for testing multiple versions, it’s worth testing the minimum jQuery version your plugin supports, and each major version above it.
At a minimum, I’d recommend testing in 1.9.x and 2.x to ensure that any differences between the two versions don’t inadvertently break your plugin. Since both versions will be developed in parallel as long as old versions of IE maintain significant market share, it’s the least we can do for our users.
Update (19 Feb 2013): This article now reflects changes made in Grunt v0.4