Javascript – Developing UI in JavaScript using TDD Principles

javascripttdduser-interface

I've had a lot of trouble trying to come up with the best way to properly follow TDD principles while developing UI in JavaScript. What's the best way to go about this?

Is it best to separate the visual from the functional? Do you develop the visual elements first, and then write tests and then code for functionality?

Best Solution

I've done some TDD with Javascript in the past, and what I had to do was make the distinction between Unit and Integration tests. Selenium will test your overall site, with the output from the server, its post backs, ajax calls, all of that. But for unit testing, none of that is important.

What you want is just the UI you are going to be interacting with, and your script. The tool you'll use for this is basically JsUnit, which takes an HTML document, with some Javascript functions on the page and executes them in the context of the page. So what you'll be doing is including the Stubbed out HTML on the page with your functions. From there,you can test the interaction of your script with the UI components in the isolated unit of the mocked HTML, your script, and your tests.

That may be a bit confusing so lets see if we can do a little test. Lets to some TDD to assume that after a component is loaded, a list of elements is colored based on the content of the LI.

tests.html

<html>
<head>
<script src="jsunit.js"></script>
<script src="mootools.js"></script>
<script src="yourcontrol.js"></script>
</head>
<body>
    <ul id="mockList">
        <li>red</li>
        <li>green</li>
    </ul>   
</body>
<script>
    function testListColor() {
        assertNotEqual( $$("#mockList li")[0].getStyle("background-color", "red") );

        var colorInst = new ColorCtrl( "mockList" );

        assertEqual( $$("#mockList li")[0].getStyle("background-color", "red") );
    }
</script>


</html>

Obviously TDD is a multi-step process, so for our control, we'll need multiple examples.

yourcontrol.js (step1)

function ColorCtrl( id ) {
 /* Fail! */    
}

yourcontrol.js (step2)

function ColorCtrl( id ) {
    $$("#mockList li").forEach(function(item, index) {
        item.setStyle("backgrond-color", item.getText());
    });
    /* Success! */
}

You can probably see the pain point here, you have to keep your mock HTML here on the page in sync with the structure of what your server controls will be. But it does get you a nice system for TDD'ing with JavaScript.