Functional testing with qUnit

jQuery

Automated testing is an essential part of application life-cycle (see Continuous Integration). In web-development we usually test: Back-end (*Unit-tests), Front-end (HTML/CSS validators, JSLint/JSHint, CSSLint, YSlow etc) and UI (functional testing). Unit-testing (Back-end, Front-end) is about checking if all the application components adhere the technical design requirements. Every unit-test simulates the application environment on which runs. Functional tests are to determine if the application as a whole ecosystem has no flaws. They run on a copy of real application environment and show if everything is ok from user prospective. You can see it as an automation of QA-engineer routine where it is possible. For functional testing widely used such frameworks as Selenium, Windmill, Twill, BusterJS. Though, if you use qUnit for front-end unit-testing, you may love the idea to use the same tool on functional testing. jQuery provides an incredible API for DOM manipulation. It can be amazing tool to simulate user behaviors and check DOM reaction.

Thanks to Michel Gotta’s post I came up with a solution.

Configuration

You just feed UiTester with the list of UIs that you want to test in the qUnit report generator file:

<div id="playground"></div>
        <h1 id="qunit-header">QUnit example</h1>
        <h2 id="qunit-banner"></h2>
        <div id="qunit-testrunner-toolbar"></div>
        <h2 id="qunit-userAgent"></h2>
        <ol id="qunit-tests"></ol>
        <div id="qunit-fixture">test markup, will be hidden</div>

<script type="text/javascript">
(function( global ) {
   "strict mode"; 
   var $ = global.jQuery; 
   $( global.document ).ready(function(){
        UiTester.init( $, {
            testsuites : [
                {suite : global.TestSuites.example1, url: "../ui-form-example.html"},
                {suite : global.TestSuites.example2, url: "../ui-widget-example.html"}
            ]
        });
    });

}( this ));
</script>

By this we assume that we have 2 pages (here just 2 HTML files) related to the test-suits examples1 and example2 respectively. So UiTester will iterate through testsuites array, loading defined url in the iframe and running the test suite corresponding the suite property.

Tests

Now let’s see what the tests look like:

var TestSuites = {
         example1: function( $ ) {
               // qUnit tests
               this.proceed();
         },
         example2: function( $ ) {
               // qUnit tests
               this.proceed();
         }
}

Every test suite receives actual jQuery instance (every UI has own) as a parameter and must have this.proceed() call. The last one telling to the suite when it’s finished and UiTester may switch to the next suite. While testing asynchronous calls that is the only way to let suite runner know all the tests are complete, very like start() trigger of QUnit.

var example = function() {
    var that = this;
    // qUnit tests
    asyncTest( "The last async test", 1, function() {
         window.setTimeout(function() {
             ok( true, "All is fine" );
             start();
             that.proceed();
         }, 500);
     });
};

Assertion helpers

Writing tests for DOM I found that I needed a helper to make the assertion flow more readable:

test( "Test DOM", function( assert ) {
        assert.nodes([
            {   node: $("selector"),
                assert: "exists",
                message: "Selector found"
            },
            {   node: $("selector"),
                assert: "visible",
                message: "Selector visible"
            },
            {   node: $("selector"),
                assert: "checked",
                message: "Selector checked"
            }
        ]);
    });

So, ui-tester.js contains extendQUnit with a set of available assertion helpers extending qUnit standard set. Currently the only helper in there is testNodes, but you can easily extend it anytime.

Now we can run report generator (/tests-js/index.html) and examine how the test pass.

Functional testing with qUnit

In Command Line

Fancy to run the tests on the console? That can be done with e.g. phantomjs:

#phantomjs run-qunit.js http://project.my/tests-js/index.html

'waitFor()' finished in 1300ms.
Tests completed in 1167 milliseconds.
25 tests of 25 passed, 0 failed.

Just don’t forget to change Default Max Timeout value in run-qunit.js.