So, like most developers I love having unit test, but I hate writing them. Really figuring out the best way to write them and have them work well, is a pain in the ass, and that is what I hate. I have spent some time recently playing with QUnit and despite the number fact that I have found a number of posts online about it, none of them have provided (in my mind) a good way to test a site. The ideas used work well for testing a library, or specific functions, but I don’t write libraries or one off functions, I develop websites. So, I have come up with a method that I like that allows me to test my sites in a way that I like.
The unit testing information I have found mainly deals with testing libraries – this is no good for me.
Testing involves putting QUnit on your page, along with its specific markup – although you can have a “debug” mode for this, it just seems like a bad idea, for a number of reasons, including it not really being an accurate representation of your page, and it does not work across page requests.
Using headless testing – it is cool, but not cross browser or even really O/S ready.
Using something like Selenium – also cool, but involves building tests using a new tool that uses java.
There are a couple of problems still with my solution, but they are pretty easy to overcome, and writing tests becomes very simple. The basic page we need to get started with the testing is this:
test markup, will be hidden
Note: We can (and probably should) actually move our tests into different .js files making it much easier to deal with as our number of tests grow.
We are doing a couple of interesting things here, first we are testing multiple pages at one time. Every time a new page loads up, we grab the jQuery refrence from inside of it, then run the tests that are specified for that page.
Another cool thing is how we get the jQuery reference for each page.
We start by loading jQuery using noConflict(true)
This is because we need to grab the jQuery instance from inside the actual website. When jQuery attaches events to DOM elements, it actually saves those events inside of itself, so although we can trigger events inside of the page itself using our external jQuery, triggering events inside of the iframe will not actually fire any events that were created inside the page. So, instead we grab the jQuery that is actually on the page and trigger the events using it. This has the added bonus that because it is the reference from inside the page we are loading, we can reference DOM nodes as though we were working that that page directly.
Here we grab the jQuery reference from inside the iframe with:
$ = window.frames.jQuery;
Note: For ANY of this to work we must adhere to SOP, this is why we load this up on a server, side by side with our site. This is why I am loading up the iframe using location.protocol + ‘//’ + location.hostname rather than typing out the URL. This will allow it to work as we move between servers and such.
One of the cool things we are doing here is tying the starting of the tests to a button, so we can get the page to any state necessary before starting the tests – such as logging in, waiting for ajax requests to finish, or navigating to somewhere specific (not that we couldn’t do these in the tests, it just gives us options.)
Also, before we run our tests we are running the 2 following commands:
$.fx.off = true;
This will make our ajax requests and animations synchronous. Although you would never do this (especially the ajax one) on a site, for our tests it is necessary to ensure that the page is ready before we perform each test.
Now that we have done this we can run our test just like we were on the page directly.
We can select elements and trigger events on them, like so:
$(elem).click(); or $(elem).trigger(‘click’);
$(elem).mousedown(); or $(elem).trigger(‘mousedown);
Test things, such as visibility:
Basically anything you would normally do. Simple and easy.
This is not a perfect way to test your events, it is however pretty good, and will let us know when we break things.
Here are some examples of tests in action. I hope this helps you get started with unit testing.