diff --git a/lib/test.js b/lib/test.js new file mode 100644 index 0000000..e95ace0 --- /dev/null +++ b/lib/test.js @@ -0,0 +1,153 @@ + + +var exec = require('child_process').exec, + util = require('util'), + events = require('events'); + + +// +// Main assertion thingy. First rough work. +// +// Thx to @visionmedia, based off supertest's Test object: +// https://github.com/visionmedia/supertest/blob/master/lib/test.js +// + + +module.exports = Test; + +// Initialize a new `Test` with the given `options` Hash object. + +function Test(o) { + this.options = o || {}; + this._body = ''; + this._status = 0; + this._command = ''; +} + +// inherits from EventEmitter + +util.inherits(Test, events.EventEmitter); + +// +// Expectations: +// +// .expect(0) +// .expect(0, fn) +// .expect(0, body) +// .expect('Some body') +// .expect('Some body', fn) +// + +Test.prototype.expect = function(a, b){ + var self = this; + + // callback + if (typeof b === 'function') this.end(b); + + // status + if (typeof a === 'number') { + this._status = a; + // body + if (b && typeof b !== 'function') this._body = b; + return this; + } + + // body + this._body = a; + + return this; +}; + +// + +Test.prototype.end = function(fn) { + this.assert(res, fn); + return this; +}; + +// +// Setup CLI location and default arguments. +// + +Test.prototype.use = function (command) { + this._command = command; + return this; +}; + +// +// Defer invoking `.end()` until +// the command is done running. +// + +Test.prototype.end = function(fn) { + var self = this; + + this.run(function(err, stdout, stderr) { + var code = err ? err.code : 0; + + self.emit('done'); + + self.assert({ + status: code, + text: (stdout || stderr), + err: err + }, fn); + }); + + return this; +}; + +// +// Add topic to current (or root) vow +// + +Test.prototype.run = function (fn) { + var cmd = this._command; + + if(!cmd) return this.emit(new Error('Cannot run withou a command. Use .use!')); + + this.emit('run'); + + // Execute defined command with arguments and passed options + exec(cmd, fn); + + return this; +}; + + +// Perform assertions and invoke `fn(err)`. + +Test.prototype.assert = function(res, fn) { + var status = this._status, + body = this._body, + isregexp = body instanceof RegExp, + expected, + actual, + re; + + // status + if (status && res.status !== status) { + return fn(new Error('expected ' + status + ', got ' + res.status), res); + } + + // body + if (body != null) { + // string + actual = util.inspect(res.text); + expected = util.inspect(body); + + if (body !== res.text) { + // regexp + if (isregexp) { + if (!body.test(res.text)) { + return fn(new Error('expected body ' + res.text + ' to match ' + body)); + } + } else { + return fn(new Error('expected ' + expected + ' response body, got ' + actual)); + } + } + } + + fn(null, res); +}; + diff --git a/main.js b/main.js new file mode 100644 index 0000000..85551fc --- /dev/null +++ b/main.js @@ -0,0 +1,10 @@ + +var Test = require('./lib/test'); + +module.exports = cli; +cli.Test = Test; + +function cli(o) { + o = o || {}; + return new Test(o); +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..dced219 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "clt", + "version": "0.0.1", + "description": "Easy way to run assertions against CLI tools.", + "main": "main.js", + "directories": { + "test": "test" +:q + }, + "scripts": { + "test": "node node_modules/mocha/bin/mocha --reporter spec" + }, + "devDependencies": { + "mocha": "~1.3.0" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..2074c4b --- /dev/null +++ b/readme.md @@ -0,0 +1,80 @@ +clt +=== + +**Inspired / Based off both +[cli-easy](https://github.com/flatiron/cli-easy) and +[supertest](https://github.com/visionmedia/supertest)** + +> A fluent (i.e. chainable) syntax for generating vows tests for CLI applications. + +> HTTP assertions made easy via super-agent. + +Description +----------- + +- Struggling with testing cli tools. +- cli-easy is super great, but designed for generating vows +- supertest is super great, but designed to make HTTP assertions via + super-agent. + +clt is nothing more than a simple, chainable API to ease the process of +testing CLI applications & tools. + +Right now, it doesn't do anything fancy and just allow you to easily +test the exit code and stdout output, and make assertions on top of +that. + +Example +------- + +It should work with any test framework, here is an example using any +test framework at all. + +```js +var cli = require('clt'); + +cli() + .use('uname') + .expect(0, 'Linux\n') + .end(function(err, stdout, stderr) { + if(err) throw err; + }); +``` + +Here's an example with mocha, note how you can pass done straight to any +of the `.expect()` calls (or `.end()`): + +```js +describe('test uname', function() { + it('respond with Linux', function(done) { + cli() + .use('uname') + .expect('should return Linux', 'Linux\n') + .expect(0, done) + }); +}); +``` + +fancier example. + +```js +describe('Testing on a wtf thing', function() { + it('should fail as expected', function(done) { + cli() + .use('wtfBinary') + .expect(127, /command not found/) + .end(done); + }); +}); +``` + +API +--- + +> tbd + +- expect(code, fn) +- expect(code, body, [fn]) +- expect(body, [fn]) +- end(fn) + diff --git a/test/cli.js b/test/cli.js new file mode 100644 index 0000000..1d0d828 --- /dev/null +++ b/test/cli.js @@ -0,0 +1,21 @@ + +var cli = require('..'); + +describe('Testing on uname', function() { + it('should return Linux ', function(done) { + cli() + .use('uname') + .expect(0, 'Linux\n') + .end(done); + }); +}); + +describe('Testing on a wtf thing', function() { + it('should fail as expected', function(done) { + cli() + .use('wtfBinary') + .expect(127, /command not found/) + .end(done); + }); +}); +