Sorter.js
<ul>
element.function Sorter(selector) { this.list = $(selector); } Sorter.prototype.sort = function() { var elements = $.makeArray(this.list.children()); elements.sort(function(itemA, itemB) { var contentA = itemA.innerHTML, contentB = itemB.innerHTML; if(contentA < contentB ) { return -1;} if(contentA == contentB) { return 0; } if(contentA > contentB ) { return 1; } }); for(var i=0; i < elements.length; i++) { this.list.append(elements[i]); } }
sort()
on the object it uses a custom comparator function that looks at the innerHTML of the list element and uses that value for the basis of the comparison. It then takes the sorted list of elements and uses jQuery’s append()
to append each element in sorted order, resulting in a reordered list.Writing our tests
sorter_test.js
, which will contain our tests. Test suites in jsTestDriver inherit from the library’s TestCase
Javascript class, so the first thing we do is define a SorterTest class.
SorterTest = TestCase("Sorter Test")
SorterTest.prototype.testSortingStrings = function() { /*:DOC += <ul id="sort-me"> <li>Biggie</li> <li>Run DMC</li> <li>Wu-Tang Clan</li> <li>Dr. Dre</li> <li>Mos Def</li> </ul>*/ var mySorter = new Sorter("#sort-me"); mySorter.sort(); var listItems = $("#sort-me").children(); var expected = ["Biggie", "Dr. Dre", "Mos Def", "Run DMC", "Wu-Tang Clan"]; assertEquals("The number of list elements", 5, listItems.length); for(var i=0; i<5; i++) { assertEquals(expected[i], listItems[i].innerHTML); } }
:DOC +=
” and adds the contents of the comment as a DOM fragment to the page, allowing us to test against it. It’s a simple and effective way of providing DOM fixtures to test any code that does DOM manipulation.
Getting things running
jsTestDriver.conf
file defines a few configuration options we’ll need to specify before we can run our tests. First you have to provide the address and port the test server will bind to, then you’ll need to specify which files you want to load during the tests. When enumerating the files you can be explicit or use a wildcard, however explicitly naming each file allows you to have control over the order they’re loaded in. In this case we want to make sure jQuery is loaded before our sorter class because jQuery is a dependency. Here’s how our jsTestDriver.conf might look:
server: http://localhost:4223
load:
- src/jquery-1.4.4.min.js
- src/sorter.js
- src-test/sorter_test.js
java -jar JsTestDriver-1.2.2.jar --config jsTestDriver.conf --port 4223
http://localhost:4223
with your browser and click “capture browser” to get it ready for testing. You can do this with any number of browsers, jsTestDriver will run your tests on all of them and report back the results. This makes it trivial to test code against many different browsers simultaneously and spot browser-specific bugs. Once the browser is captured you don’t need to interact with it anymore, jsTestDriver will handle the rest.
java -jar JsTestDriver-1.2.2.jar --config jsTestDriver.conf --tests all
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (8.00 ms)
Firefox 3.6.13 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (8.00 ms)
SorterTest.prototype.testSortingNumbers = function() { /*:DOC += <ul id='sort-me'> <li>200</li> <li>101</li> <li>100</li> <li>1001</li> </ul>*/ var mySorter = new Sorter("#sort-me"); mySorter.sort(); var listItems = $("#sort-me").children(); var expected = [100, 101, 200, 1001]; assertEquals("The number of list elements", 4, listItems.length); for(var i=0; i<4; i++) { assertEquals(expected[i], listItems[i].innerHTML); } }
SorterTest.prototype.assertListOrder = function(expected, listItems) { assertEquals("Number of list elements", expected.length, listItems.length); for(var i=0; i < listItems.length; i++) { assertEquals(expected[i], listItems[i].innerHTML); } }
SorterTest.prototype.testSortingNumbers = function() { /*:DOC += <ul id='sort-me'> <li>200</li> <li>101</li> <li>100</li> <li>1001</li> </ul>*/ var mySorter = new Sorter("#sort-me"); mySorter.sort(); var listItems = $("#sort-me").children(); var expected = [100, 101, 200, 1001]; this.assertListOrder(expected, listItems); }
.F
Total 2 tests (Passed: 1; Fails: 1; Errors: 0) (12.00 ms)
Firefox 3.6.13 Mac OS: Run 2 tests (Passed: 1; Fails: 1; Errors 0) (12.00 ms)
Sorter Test.testSortingNumbers failed (3.00 ms): expected 101 but was "1001"
/src-test/sorter_test.js:6
/src-test/sorter_test.js:36
Tests failed.
function Sorter(selector) { this.list = $(selector); } Sorter.prototype.sort = function() { var elements = $.makeArray(this.list.children()); elements.sort(function(itemA, itemB) { var contentA = itemA.innerHTML, contentB = itemB.innerHTML; contentA = parseFloat(contentA) || contentA; contentB = parseFloat(contentB) || contentB; if(contentA < contentB ) { return -1;} if(contentA == contentB) { return 0; } if(contentA > contentB ) { return 1; } }); for(var i=0; i < elements.length; i++) { this.list.append(elements[i]); } }
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (5.00 ms)
Firefox 3.6.13 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (5.00 ms)
Integrating with Hudson
--testOutput
flag. Add the “Publish JUnit test result report” post-build action in Hudson to watch for jsTestDriver’s reports and Hudson will use the XML output to provide information about historical trends as well as a nice web-based UI to browse test results.