in·dom·i·ta·ble
adj.
Incapable of being overcome, subdued, or vanquished; unconquerable.
8th
APR
Javascript for Grown-Ups: Setting up the DOM
Posted by indomitablehef | Filed under jQuery, qUnit, TDD
When testing javascript and jQuery code, I find I’m often adding elements here and there to the DOM, usually appending to a div. In such cases, I try to write my functions such that I pass in the container div as a selector. For example:
function AddToyToBox(toy, box) { var toyId = toy.Name.replace(/ /g, ''); //remove spaces from the name $('<div id="' + toyId + '"></div>').addClass('toy').appendTo(box); }
In this trivial example, we’re taking a “toy” object, creating a div for it, and adding it to some element in the DOM that represents a “box”, probably another div.
The qUnit test for this method, then, looks like this: (using my custom Assertions, described here)
test("Can Add Toy to ToyBox", function() { var toy = new Toy('Monster Truck'); var expectedToyBoxHtml = "<div class=\"toy\" id=\"MonsterTruck\"></div>"; AddToyToBox(toy, '#stubToyBoxDiv'); Assert.AreEqual(expectedToyBoxHtml, $('#stubToyBoxDiv').html()); });
Notice the reference to #stubToyBoxDiv. In my tests.html file, I was putting some “stub” html at into a div at the bottom of the file, so that I would have a container to drop my elements into when testing methods like AddToToBox(). I even had a clever way to clean up after myself after I was done - I made my last test remove the div that contained all my stub container divs. This quickly became a pain, however, because I found myself needing to have #stubToyBoxDiv1, #stubToyBoxDiv2, etc.
But thanks to jQuery, there is a much better and more elegant way to do this than littering up your tests.html file with stub divs. Instead, just create the dom element you need as part of your test setup, and remove it when you’re done:
test("Can Add Toy to ToyBox", function() { var toy = new Toy('Monster Truck'); var expectedToyBoxHtml = "<div class=\"toy\" id=\"MonsterTruck\"></div>"; $('<div id="stubToyBoxDiv"/>').appendTo('body'); AddToyToBox(toy, '#stubToyBoxDiv'); Assert.AreEqual(expectedToyBoxHtml, $('#stubToyBoxDiv').html()); $('#stubToyBoxDiv').remove(); });
I added the following DOMSetup and DOMTeardown methods, for better test readability:
DOMSetup = function(element, container) { var el = $(element); if (container != null) el.appendTo(container); else el.appendTo('body'); } DOMTearDown = function(selector) { $(selector).remove(); }
So now my test can look like this:
test("Can Add Toy to ToyBox", function() { var toy = new Toy('Monster Truck'); var expectedToyBoxHtml = "<div id=\"MonsterTruck\" class=\"toy\"></div>"; DOMSetup('<div id="stubToyBoxDiv"/>'); AddToyToBox(toy, '#stubToyBoxDiv'); Assert.AreEqual(expectedToyBoxHtml, $('#stubToyBoxDiv').html()); DOMTearDown('#stubToyBoxDiv'); });
7th
APR
Javascript for Grown-Ups: an Assertion Helper for qUnit
Posted by indomitablehef | Filed under jQuery, qUnit, TDD
In an effort to write my jQuery and Javascript code with the same rigor I use when writing my c# and even Sql code, I’ve started using the qUnit testing framework. qUnit is the unit testrunner for the jQuery project.
So far, I’m loving it, with a only few caveats. For one, I would like to write more BDD-style tests, and though I can sort of do it, it’s not very expressive. At some point, I’m going to want to try out JSpec, but for now I’m going to keep on working with qUnit.
Antother issue is that I don’t find it very expressive. For example, the AssertAreEqual function is called just “equals(actual, expected)”, and the AssertIsTrue method is just “ok(actual, expected)”. I miss my Assert.AreEqual and Asssert.IsTrue expressiveness, and I don’t like having “actual” come before “expected” in the parameter list.
So, I wrote this little AssertionHelper to help make my tests more expressive:
function AssertionHelper() { this.IsTrue = function(bool, message) { ok(bool,message); }; this.IsFalse = function(bool, message) { ok(!bool,message); }; this.AreEqual = function(expected, actual, message) { equals(actual, expected, message); }; this.AreNotEqual = function(expected, actual, message) { ok(actual != expected, message); }; this.AreSame = function(expected, actual, message) { same(actual, expected, message); } }
Now, in my tests.js file, I can just declare a variable called Assert as a new AssertionHelper, and use it in my tests to get the familiar expressiveness and semantics of the xUnit family of testing frameworks.
var Assert = new AssertionHelper(); $(document).ready(function() { test("a basic test example", function() { // instead of: ok(true, "this test is fine"); //use Assert.IsTrue(true); Assert.IsTrue(true, "this test is fine"); Assert.IsFalse(false); Assert.IsFalse(false, "this test is fine"); var value = "hello"; //instead of: equals("hello", value, "We expect value to be hello"); //use Assert.AreEqual(value, "hello"); Assert.AreEqual(value, "hello", "We expect value to be hello"); Assert.AreNotEqual(value, "goodbye"); Assert.AreNotEqual(value, "goodbye", "We expect value to be hello"); Assert.AreNotEqual(value, "hello"); Assert.AreNotEqual(value, "hello", "this test and the one before it should fail"); var x = { "name": "myobject" }; var y = x; var z = { "name": "myobject2" }; Assert.AreSame(y, x); Assert.AreSame(y, x, "these two should be the same"); Assert.AreSame(z, x, "this test should fail"); }); });
UPDATE: Reader ToneD shared the following improvement in the comments. He’s using a static class, which negates the need for instantiation and gives you intellisense on the Assert methods:
Assert = { IsTrue: function(bool, message) { ok(bool, message); }, IsFalse: function(bool, message) { ok(!bool, message); }, AreEqual: function(expected, actual, message) { equals(actual, expected, message); }, AreNotEqual: function(expected, actual, message) { ok(actual != expected, message); }, AreSame: function(expected, actual, message) { same(actual, expected, message); } }
Recent Posts
Recent Comments
- Open Floor Plan vs. Private Offices « Step Into Design on It's Caves AND Commons...
- indomitablehef on Forms Authentication in Asp.Net MVC, Part II
- Dugald Wilson on Forms Authentication in Asp.Net MVC, Part II
- MyWeeklyLinks – Week 5 « Ole Morten Amundsen on Implementing Done, In Process, and Ready Queues in LeanKit Kanban
- indomitablehef on Schema Generation using FluentNHibernate and S#arp Architecture
Categories
- .Net (5)
- Agile (17)
- Alt.Net (3)
- Anti Patterns (3)
- Asp.Net MVC (9)
- Continuous Integration (4)
- Craftsmanship (1)
- CruiseControl.Net (1)
- DDD (6)
- DevLink (2)
- jQuery (2)
- Kanban (4)
- Lean (2)
- LeanKit (3)
- NAnt (2)
- NHibernate (2)
- ORM (1)
- Personal (4)
- Productivity (6)
- qUnit (2)
- Refactoring (1)
- S#arp Architecture (2)
- SOLID (1)
- SqlTdd (5)
- TDD (17)
- Tools (12)
- Uncategorized (11)
- Visual Studio (4)


