Skip to content

Commit

Permalink
First working version
Browse files Browse the repository at this point in the history
  • Loading branch information
felixge committed Nov 13, 2011
1 parent ce1bc5e commit 4b9ecf3
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 0 deletions.
56 changes: 56 additions & 0 deletions Readme.md
@@ -0,0 +1,56 @@
# utest

The minimal unit testing library.

## Usage

Running a test with utest is very simple:

```js
var test = require('utest');
var assert = require('assert');

test('Number#toFixed', {
'returns a string': function() {
assert.equal(typeof (5).toFixed(), 'string');
},

'takes number of decimal places': function() {
assert.equal((5).toFixed(1), '5.0');
},

'does not round': function() {
assert.equal((5.55).toFixed(1), '5.5');
},
});
```

The only additional feature is running a before/after method:

```js
var test = require('utest');
var assert = require('assert');

test('Date', {
before: function() {
this.date = new Date;
},

after: function() {
this.date = null;
},

'lets you manipulate the year': function() {
this.date.setYear(2012);
assert.equal(this.date.getFullYear(), 2012);
},

'can be coerced into a number': function() {
assert.equal(+this.date, 'number');
},
});
```

## License

This module is licensed under the MIT license.
16 changes: 16 additions & 0 deletions index.js
@@ -0,0 +1,16 @@
module.exports = utest;
utest.Collection = require('./lib/Collection');
utest.TestCase = require('./lib/TestCase');
utest.BashReporter = require('./lib/reporter/BashReporter');

var collection;
var reporter;
function utest(name, tests) {
if (!collection) {
collection = new utest.Collection();
reporter = new utest.BashReporter({collection: collection});
}

var testCase = new utest.TestCase({name: name, tests: tests});
collection.add(testCase);
};
33 changes: 33 additions & 0 deletions lib/Collection.js
@@ -0,0 +1,33 @@
var util = require('util');
var EventEmitter = require('events').EventEmitter;

module.exports = Collection;
util.inherits(Collection, EventEmitter);
function Collection(options) {
this._pass = 0;
this._fail = 0;
}

Collection.prototype.add = function(testCase) {
this._start = this._start || Date.now();

var self = this;
testCase
.on('pass', function(name) {
self._pass++;
self.emit('pass', testCase, name);
})
.on('fail', function(name, err) {
self._fail++;
self.emit('fail', testCase, name, err);
})
.run();
};

Collection.prototype.stats = function() {
return {
pass : this._pass,
fail : this._fail,
duration : Date.now() - this._start,
};
};
36 changes: 36 additions & 0 deletions lib/TestCase.js
@@ -0,0 +1,36 @@
var util = require('util');
var EventEmitter = require('events').EventEmitter;

module.exports = TestCase;
util.inherits(TestCase, EventEmitter);
function TestCase(properties) {
this.name = properties.name;
this._tests = properties.tests;
}

TestCase.prototype.run = function() {
var noop = function() {};
var before = this._tests.before || noop;
var after = this._tests.after || noop;

for (var test in this._tests) {
if (test === 'before' || test === 'after') continue;

var fn = this._tests[test];
var context = {};

try {
before.call(context);
fn.call(context);
after.call(context);
} catch (_err) {
var err = _err;
}

if (!err) {
this.emit('pass', test);
} else {
this.emit('fail', test, err);
}
}
};
26 changes: 26 additions & 0 deletions lib/reporter/BashReporter.js
@@ -0,0 +1,26 @@
module.exports = BashReporter;
function BashReporter(options) {
this._process = options.process || process;
this._collection = options.collection;

this._collection.on('fail', this.handleFail.bind(this));
this._process.on('exit', this.handleExit.bind(this));
}

BashReporter.prototype.handleFail = function(testCase, test, error) {
this._process.stdout.write('Fail: ' + testCase.name + ': ' + test + '\n');
this._process.stdout.write(error.stack + '\n\n');

};

BashReporter.prototype.handleExit = function() {
var stats = this._collection.stats();
this._process.stdout.write(
stats.fail + ' fail | ' +
stats.pass + ' pass | ' +
stats.duration + ' ms ' +
'\n'
);

if (stats.fail) this._process.reallyExit(1);
};
24 changes: 24 additions & 0 deletions test/system/test-example.js
@@ -0,0 +1,24 @@
var assert = require('assert');
var test = require('../..');

var executed = 0;
test('Number#toFixed', {
'returns a string': function() {
assert.equal(typeof (5).toFixed(), 'string');
executed++;
},

'takes number of decimal places': function() {
assert.equal((5).toFixed(1), '5.0');
executed++;
},

'does not round': function() {
assert.equal((5.55).toFixed(1), '5.5');
executed++;
},
});

process.on('exit', function() {
assert.equal(executed, 3);
});
66 changes: 66 additions & 0 deletions test/unit/test-Collection.js
@@ -0,0 +1,66 @@
var assert = require('assert');
var Collection = require('../../lib/Collection');
var TestCase = require('../../lib/TestCase');

(function testRunningTwoTestCases() {
var caseA = new TestCase({
name: 'a',
tests: {
'1': function() {},
'2': function() {},
},
});
var caseB = new TestCase({
name: 'b',
tests: {
'3': function() {},
'4': function() {},
},
});

var collection = new Collection();

var pass = [];
collection.on('pass', function(testCase, name) {
pass.push(testCase.name + ':' + name);
});

collection.add(caseA);
collection.add(caseB);

assert.deepEqual(pass, ['a:1', 'a:2', 'b:3', 'b:4']);

var stats = collection.stats();
assert.equal(stats.pass, 4);
})();

(function testFailingTestCase() {
var testCase = new TestCase({
tests: {
'good test': function() {
},
'bad test': function() {
throw new Error('failure');
}
},
});

var collection = new Collection();

var fail = [];
collection.on('fail', function(testCase, name, error) {
fail.push({testCase: testCase, name: name, error: error});
});

collection.add(testCase);

assert.equal(fail.length, 1);
assert.equal(fail[0].testCase, testCase);
assert.equal(fail[0].name, 'bad test');
assert.equal(fail[0].error.message, 'failure');

var stats = collection.stats();
assert.equal(stats.pass, 1);
assert.equal(stats.fail, 1);
assert.ok(stats.duration >= 0);
})();
71 changes: 71 additions & 0 deletions test/unit/test-TestCase.js
@@ -0,0 +1,71 @@
var assert = require('assert');
var TestCase = require('../../lib/TestCase');

(function testRunEmitsPassAndFail() {
var test = new TestCase({tests: {
a: function() {
assert.equal(1, 1);
},
b: function() {
assert.equal(2, 1);
},
}});

var fail = [];
var pass = [];

test
.on('pass', function(name) {
assert.equal(name, 'a');
pass.push(name);
})
.on('fail', function(name, err) {
assert.ok(err instanceof Error);
assert.equal(name, 'b');
fail.push(name);
});


test.run();

assert.equal(pass.length, 1);
assert.equal(fail.length, 1);
})();

(function testBeforeAndAfter() {
var events = [];
var test = new TestCase({tests: {
before: function() {
events.push('before');
},
after: function() {
events.push('after');
},

a: function() {
events.push('a');
},
}});

test.run();

assert.deepEqual(events, ['before', 'a', 'after']);
})();

(function testBeforeAndAfterContext() {
var aCalled = false;
var test = new TestCase({tests: {
before: function() {
this.foo = 'bar';
},

a: function() {
assert.deepEqual(this, {foo: 'bar'});
aCalled = true;
},
}});

test.run();

assert.ok(aCalled);
})();

0 comments on commit 4b9ecf3

Please sign in to comment.