bebraw
5/4/2011 - 1:40 PM

run_tests.js

tests('Assert', {
    _: {
        a: 5
    },
    equals: function() {
        assert(this.a).equals(5);
    },
    not: function() {
        assert(this.a).not().equals(6);
    }
    ...
});
tests('<set name>', {
    _: {}, // set up
    <test name>: <test>
});
var tests = function(setName, newTests) {
    var scope = this;
    
    if(!('testsToRun' in this)) {
        this.testsToRun = [];
    }
    
    if(setName && newTests) {
        this.testsToRun.push({name: setName, tests: newTests});
    }
    
    var clone = function(o) {
        // http://www.andrewsellick.com/93/javascript-clone-object-function
        if(typeof(o) != 'object' || !o) {
            return o;
        }

        var newO = new Object();

        for(var i in o) {
            newO[i] = clone(o[i]);
        }

        return newO;
    }
    
    return {
        run: function(output) {
            var passedTests = 0;
            var testTotal = 0;

            for(var i = 0; i < scope.testsToRun.length; i++) {
                var model = scope.testsToRun[i];
                var testSet = model.tests;
                
                var attrs = testSet._ || {};
                delete testSet._;

                output({state: 'started', text: 'Running "' + model.name + '" tests'});

                for(var testName in testSet) {
                    var test = testSet[testName];

                    try {
                        test.apply(clone(attrs));

                        output({state: 'passed', text: 'PASSED: ' + testName});

                        passedTests++;
                    }
                    catch(e) {
                        output({state: 'failed', text: 'FAILED: ' + testName});
                        output({state: 'error', text: e});
                    }

                    testTotal++;
                }
            }

            output({state: 'finished', text: passedTests + '/' + testTotal + ' tests passed'});
        }
    };
};
var outputArea = document.getElementById('testOutput');

var HTMLOutput = function(report) {
    outputArea.innerHTML += '<div class="' + report.state +
        '">' + report.text + '</div>';
};

var consoleOutput = function(report) {
    // for some reason console.log won't work at chrome
    // "as is". it's better to wrap it like this
    console.log(report.text);
};

// swap output based on your needs
// you could also join them and feed it to many places
tests().run(HTMLOutput);