BDD Testing of jQuery plugins using Jasmine


Jasmine is a simple, straightforward behavior-driven development framework for JavaScript. One of its core principles is that it “should not be tied to any browser, framework, platform, or host language.” This makes it excellent for testing bare JavaScript code. But this does mean, it’s not entirely obvious how one would would test code that is tied to a browser and framework. Like for example, a jQuery plugin.

To demonstrate this, I’ve put together a super simple (read: completely useless) jQuery plugin which will make any list, a slightly editable list. Check it out on jsFiddle.net – just put something in the text box then hit enter. It’ll add items to the list and provide a link on each item to remove it.

Jasmine couldn’t be easier to explain. You have suites, and you have specifications. Suites describe scenarios; specifications describe what it should be doing in those scenarios. Those two things are the only two methods you have to know, describe and it.

It’s best demonstrated by example. I feel the only bit of this that requires an explanation is the beforeEach method. This is run before each specification, and I use it to initialize my jQuery plugin. I’ve extended Jasmine with jasmine-jquery, a smart little library that helps us initialize jQuery related bits. It’s what allows us to setup the HTML which the fixture runs against, and then in our beforeEach initialize our plugin.

describe("jquery.list", function() {
	var textbox, list;

	beforeEach(function() {
		jasmine.getFixtures().set('<input id="textbox" type="text" />
<ul id="list">');
		textbox = $('#textbox');
		list = $('#list').list({
			input: textbox
		});
	});

	describe("pressing enter in input when there's no value", function() {
		beforeEach(function() {
			var keypress = $.Event('keypress');
			keypress.which = $.ui.keyCode.ENTER;

			textbox.val('');

			textbox.trigger( keypress );
		});

		it("should not add an item", function() {
			expect( list ).toBeEmpty();
		});
	});
});

Hopefully you found that clear. In the preceding code sample, we set up the scenario that the text box is empty and that the enter key had been pressed. Then using the it method, we expect that the list should be empty.

What I really like about Jasmine, is something anyone who is familiar with RSpec will appreciated – nested specifications. It’s something I feel that particularly makes sense in UI testing. In our case, we have a scenario to add an item and write some specifications to verify that. Once that item’s been added, we can then have another nested scenario that we can remove it.

describe("pressing enter in input when it's got a value", function() {
	var testText = 'THIS IS SOME TEXT';

	beforeEach(function() {
		// omitted code to set test text and press enter key
	});

	it("should add item to list", function() {
		expect( list.children().length ).toEqual( 1 );
	});

	it("item should contain entered text", function() {
		expect( list.find( 'li' ).text() ).toContainText( testText )
	});

	describe("clicking remove link", function() {
		it("should remove item", function() {
			var click = $.Event('click');
			list.find('li a').trigger( click );

			expect( list ).toBeEmpty();
		});
	});
});

Note how we have a describe method nested inside a describe. The first adds the item, the second then removes it. It’s using techniques like this that I find writing BDD style specifications are much more effective at testing front-end code than traditional unit-testing.

Run the specifications yourself here. Download all the code here.

About these ads

5 thoughts on “BDD Testing of jQuery plugins using Jasmine

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s