Javascript Unit Testing, Test Pages (test classes).

I have known about javascript testing for a while, about a year. I mostly wrote it off as something “too advanced” for me. I looked at it as overkill, and in the past just have not had the time to take it seriously, despite TDD changing the way I do things server side.

Well I finally took the plunge. At first I took a look at qUnit. Right away I liked/hated some things about qunit. Most of all I hated that everyone seemed to be using multiple assertions per test function. And not the honest usage of a “guard” assertion here or there. They were blatantly testing distinct features from within the same method.

Not to gripe about their choice of style, but for me I had an extra requirement. Back when I thought js testing was not needed I coupled lots of PHP code with my javascript file. Depending on settings in PHP different js sections get created, and I want to test that. To do this I need each group of tests to live in it’s own page. I needed each page to run one after the other so each page can change some state on server side. I need them to run one after the other, synchronously so that the tests do not interact via the “global” state that is changing on the server.

After reading through both the source code of qunit and jsunit, here is what I found

jsunit supports test pages
jsunit does NOT support asynchronous tests.
qunit supports asynchronous tests
qunit does NOT support test pages.

After finding the relevant parts of both test frameworks, I decided it would be easier to hack in test page support for qunit, rather then to try to add asynch support for jsunit.

First all of my files live *outside* of the web root since I am testing a plugin for Magento. So first I created a file that can include them, which is how jsunit works, each test page has a URL. Then I wrote up this quick code. You can see there is an array of file names. runSuite() runs the “currentPage”. it loads the page by loading the test page into an iframe. When it is complete it uses qunit hooks to alert the “runner”.

Simply open your qunit pages and place this callback:

QUnit.done = function (failures, total) {
top.testPageComplete( ‘<?=basename(__FILE__)?>’, failures, total );
};

This simply tells my runner (below) when the page is done. It says which page, and how many tests/failures happened.

Then create the runner and load it in your browser:

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”
“http://www.w3.org/TR/html4/loose.dtd”>
<html>
<head>
<style type=”text/css”>
a{
display: block;
}
</style>
<script src=”http://localhost.vehiclefits.com/skin/adminhtml/default/default/jquery-1.3.2.min.js”> </script>
<script type=”text/javascript”>
var testPages = new Array( ‘ajaxTestJsMMY.php’, ‘ajaxTestJsMMTC.php’, ‘ajaxTestJsMMYdisabled.php’ );

var currentPage = 0;

var iframeForLink = function( link ) {
return $(link).next(‘iframe’);
}

var toggleIframe = function( link ) {
iframeForLink( link ).toggle();
}

var bindToggles = function() {
$(‘.pageFrameToggle’).unbind(‘click’);
$(‘.pageFrameToggle’).click( function() {
toggleIframe(this);
});
}

var loadPage = function(page) {
var pageName = testPages[page];
$(‘#testPageContainer’).append( ‘<a href=”#”>’ + pageName + ‘</a>’ );
bindToggles();
$(‘#testPageContainer’).append( ‘<iframe src=”/vafJsTest.php?file=’ + pageName + ‘” width=”500″ height=”500″></iframe>’ );
}

var areMorePages = function() {
return currentPage < testPages.length;
}

var runCurrentPage = function() {
loadPage( currentPage );
currentPage++;
}

var getPageIndex = function( pageName ) {
var i = 0;
while( i < testPages.length ) {
if( pageName == testPages[i] ) {
return i;
}
i++;
}
return false;
}

var testPageComplete = function( testPage, failures, total ) {
var result = failures + ‘ failures, ‘ + total + ‘ total<br />’;
//$(‘#testPageResults’).append( testPage + ‘ ‘ + result );
var selector = ‘.page’ + getPageIndex( testPage );
$(selector).append( ‘ | ‘ + result ).click();
if( areMorePages() ) {
runCurrentPage();
}
}

var runSuite = function() {
runCurrentPage();
}
$(document).ready( runSuite );

</script>
</head>
<body>
<div id=”testPageResults”></div>
<div id=”testPageContainer”></div>
</body>
</html>

So once it again it just loops thru the array of test Pages, and “includes” their url via the iframe. It does it serially so that no page begins before the previous completely finishes. And best of all it does it with the core qUnit stuff, without changing it… Qunit rocks for asynchronous testing.

Which is another topic. I’ll have to give a ping back to Anup Shah for teaching me that art.

This entry was posted in Uncategorized. Bookmark the permalink.

One Response to Javascript Unit Testing, Test Pages (test classes).

  1. Sky Sanders says:

    Hey Josh,
    Great idea!
    I had the same idea – you can check it out @ http://salientqc.codeplex.com/SourceControl/changeset/view/41905#721642 .
    I think you will like it.

    keep on coding…

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>