SpeckTest tools on top of Vows | |
| lib/assert/macros.js |
Module imports
|
var vows = require( 'vows' );
var assert = require( 'assert' );
|
Module exports
|
exports.isBuffer = isBuffer;
|
assert extensions
|
assert.isBuffer = isBuffer;
|
Buffer instance assertion
Examples
assert.isBuffer( new( Buffer ), '{actual} is not a Buffer' );
|
function isBuffer ( actual, message ) {
if ( !( actual instanceof Buffer ) ) {
assert.instanceOf( actual, Buffer, message || 'expected {actual} to be an instance of Buffer', 'instanceof', assert.instanceOf );
}
}
|
| lib/klient.js |
Module imprts
|
var _ = require( 'underscore' )._;
var util = require( 'util' );
var http = require( 'http' );
var events = require( 'events' );
var Buffer = require('buffer').Buffer;
|
Module exports
|
exports.Klient = Klient;
|
Client Abstraction for HTTPServer/API tests
type: Function param: options return: Klient
|
function Klient ( config ) {
events.EventEmitter.call( this );
this.options = _.extend( {}, this.defaults, config || {} );
this.server = this.options.server;
this.deferred = [];
this.started = false;
this.pending = false;
}
util.inherits( Klient, events.EventEmitter );
|
Defaults
type: Object param: String host param: Number port
|
Klient.prototype.defaults = {
host: 'localhost',
port: 8081,
path: '/'
};
|
Handles queued requests
|
Klient.prototype.processDeferred = function () {
var self = this;
var deferred = self.deferred;
process.nextTick( function () {
_( deferred.length ).times( function () {
self.request( deferred.shift() );
});
});
};
|
Wrapper for request method to return a promise
type: Function param: Object options return: EventEmitter
|
Klient.prototype.promisedRequest = function ( options ) {
var self = this;
var promise = new( events.EventEmitter );
options.promise = promise;
self.request( options );
return promise;
};
|
Binding of test server
|
Klient.prototype.listen = function ( callback ) {
var self = this;
var server = self.server;
var host = self.options.host;
var port = self.options.port;
var callback;
cb = function () {
self.pending = false;
self.started = true;
self.processDeferred();
if ( _.isFunction( callback ) ) {
callback();
}
};
self.pending = true;
server.listen( port, host, cb );
};
|
Closes test server
|
Klient.prototype.close = function() {
this.server.close();
};
|
Main request logic with lazy binding of test server
type: Function param: Object options
|
Klient.prototype.request = function ( options ) {
var self = this;
var server = self.server;
var promise = options.promise;
var req;
if ( server && ( !server.fd || !self.started ) ) {
self.deferred.push( options );
if( !self.started && !self.pending ) {
self.listen();
}
return;
}
options = _.extend( {}, self.options, options );
req = http.request( options );
process.nextTick( function () {
req.on( 'response', function ( res ) {
var body = new( Buffer )(0);
res.on('data', function(chunk) {
var buffer = new( Buffer )( body.length + chunk.length );
body.copy( buffer );
chunk.copy( buffer, body.length );
body = buffer;
});
res.on('end', function() {
if ( res.headers['content-type'] === 'application/json' ) {
body = JSON.parse( body.toString() );
}
res.body = body;
promise.emit( 'success', res );
});
}).on( 'error', function ( err ) {
promise.emit( 'error', err );
});
if ( _.isArray( options.data ) ) {
_.each( options.data, function (data) {
req.write( data );
});
} else if ( options.data ) {
req.write( options.data );
}
req.end()
});
};
|
GET convenience method
type: Function return: EventEmitter
|
Klient.prototype.get = function ( options ) {
_.extend( options, { method: 'get' } );
return this.promisedRequest( options );
}
|
POST convenience method
type: Function return: EventEmitter
|
Klient.prototype.post = function ( options ) {
_.extend( options, { method: 'post' } );
return this.promisedRequest( options );
}
|
PUT convenience method
type: Function return: EventEmitter
|
Klient.prototype.put = function ( options ) {
_.extend( options, { method: 'put' } );
return this.promisedRequest( options );
}
|
DELETE convenience method
type: Function return: EventEmitter
|
Klient.prototype.del = function ( options ) {
_.extend( options, { method: 'delete' } );
return this.promisedRequest( options );
}
|
| lib/makros.js |
Module imports
|
var _ = require( 'underscore' )._;
var assert = require( 'assert' );
|
Module exports
|
exports.body = body;
exports.header = header;
exports.request = request;
exports.status = status;
|
Deep equality response body test
|
function body ( value ) {
return function ( err, res ) {
assert.ifError( err );
assert.deepEqual( res.body, value );
}
}
|
Arbitary header test macro
|
function header ( name, value ) {
return function ( err, res ) {
assert.ifError( err );
assert.equal( res.headers[name], value );
}
}
|
statusCode test macro
|
function status ( code ) {
return function ( err, res ) {
assert.ifError( err );
assert.equal( res.statusCode, code );
}
}
|
Request/Response cycyle macro
type: Function param: Object request Options for the http request param: Object response Criteria the response should match param: Object vows Arbitary vows to be executed return: Function
|
function request ( request, response, vows ) {
var context;
context = {
topic: function ( client ) {
var nameSplit = this.context.name.split(/ +/);
var method = request.method || nameSplit[0].toLowerCase();
var path = request.path || nameSplit[1];
request = _.extend({
method: method,
path: path
}, request );
return client[( method === 'delete' ) ? 'del' : method]( request );
}
};
if ( response.status ) {
context['should respond with *' + response.status + '*'] = status( response.status );
}
if ( response.headers ) {
_.each( response.headers, function ( value, key ) {
context['should return ' + key + ': *' + value + '*'] = header( key, value );
});
}
if ( response.body ) {
context['should send correct *body*'] = body( response.body );
}
if ( vows ) {
_.each( vows, function ( vow, name ) {
context[name] = vow;
})
}
return context;
}
|