Skip to content

Instantly share code, notes, and snippets.

@grncdr
Created June 14, 2014 21:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grncdr/6065f3448a73ae364706 to your computer and use it in GitHub Desktop.
Save grncdr/6065f3448a73ae364706 to your computer and use it in GitHub Desktop.
testing API's with buster
'use strict';
var buster = require('buster');
var testApi = require('./test-http');
function exampleApp () {
return function (req, res) {
res.setHeader('content-type', 'text/plain');
res.setHeader('content-length', req.url.length);
res.end(req.url);
};
}
buster.testCase('Echo server', testApi(exampleApp, {
// You can use `this.request(path, options)` in setUp
setUp: function () {
this.expectedContentType = 'text/plain';
},
// Using tearDown to assert common post-conditions
tearDown: function () {
if (this.response) {
buster.assert.equals(this.response.headers['content-type'],
this.expectedContentType,
'Maybe you need to set this.expectedContentType in your test?');
}
},
'GET /a/static/path': function (response) {
// Use an argument, or not.
buster.assert.same(this.response, response);
buster.assert.equals('/a/static/path', response.body);
},
'GET /a/:parameterized/path': {
// use getParams on individual requests. This can also return a promise.
getParams: function () {
return { parameterized: 'something' };
},
assertions: function (response) {
buster.assert.equals(response.body, '/a/something/path');
}
}
}));
'use strict';
var http = require('http');
var url = require('url');
var Promise = require('bluebird');
var questor = require('questor');
var buster = require('buster');
module.exports = function testHttpApp (createApp, tests) {
Object.keys(tests).forEach(function (key) {
var match = key.match(/^(GET|PUT|POST|DELETE|HEAD) (\/[^ ]*)$/);
if (match) {
var test = createRequestTest(createApp, match[1], match[2], tests[key]);
tests[test.testName || key] = test;
}
});
tests.setUp = before(tests.setUp, function (next) {
var self = this;
this.app = createApp();
this.server = http.createServer(this.app)
.listen(0, 'localhost')
.on('listening', function () {
var port = self.server.address().port;
self.request = function (path, options) {
var uri = url.format({
hostname: 'localhost',
port: port,
protocol: 'http:',
pathname: path
});
return questor(uri, options);
};
next();
});
});
tests.tearDown = before(tests.tearDown, function (next) {
this.server.close();
this.server.on('close', next);
});
return tests;
};
function createRequestTest (createApp, method, path, test) {
return function () {
var self = this;
if (typeof test !== 'object' || !test.assertions) {
test = {
assertions: test
};
}
var params = test.getParams ? test.getParams.call(this) : {};
return Promise.resolve(params).then(function (params) {
if (params) {
path = path.replace(/:(\w+)/g, function (_, name) {
if (name in params) {
return params[name];
} else {
throw new Error('Parameter not defined: ' + name);
}
});
}
var options = { method: method };
if (test.headers) { options.headers = test.headers; }
if (test.body) { options.body = test.body; }
return self.request(path, options).then(function (response) {
self.response = response;
return checkResponse(self, test.assertions, response);
});
});
};
}
function checkResponse (test, assertions, response) {
if (typeof assertions === 'function') {
return assertions.call(test, response);
}
if (Array.isArray(assertions)) {
return Promise.reduce(assertions, function (_, assertion) {
return assertion.call(test, response).return(_);
});
}
if (typeof assertions === 'object') {
buster.assert.match(response, assertions);
}
}
function before (original, first) {
return function (done) {
var self = this;
first.call(self, function () {
if (original) {
original.call(self, done);
if (!original.length) {
done();
}
} else {
done();
}
});
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment