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);