seahorse
Version:
Configurable mock REST API testing tool written in javascript
1,203 lines (1,118 loc) • 37.9 kB
JavaScript
/*! seahorse - v0.2.6 - 2016-06-18 */
(function(global){
'use strict';
var fs = require('fs');
var Throttle = require('throttle');
var util = require('util');
var BASE_RATE = 2 * 1000 * 1000 / 8; // 2MBps = 2Mbps/8
var utils = {
_debug : false,
_logs : false,
_cors : true,
_proxy : false,
_th : null,
_bps : BASE_RATE,
_getExtension: function(filename) {
var i = filename.lastIndexOf('.');
return (i < 0) ? '' : filename.substr(i);
},
_setRate: function(newrate) {
if (this._th) this._th.setBps(newrate);
this._bps = parseInt(newrate);
},
_getRate: function() {
return this._bps;
},
_sendfile: function(filename, res) {
var stream = fs.createReadStream(filename);
var self = this;
this._th = new Throttle(this._bps);
stream.on('open', function() {
if( utils._debug ) {
util.log('[info] open ' + filename);
}
// automaticaly pipes readable stream to res (= writeableStream), data are then transfered
// with a limited rate through the throttle
stream.pipe(self._th).pipe(res);
});
stream.on('data', function(chunk) {
if( utils._debug ) {
util.log('[info] read a chunk :' + chunk.length + ' bytes');
}
});
stream.on('close', function(chunk) {
if( utils._debug ) {
util.log('closed ' + filename);
}
});
stream.on('error', function(err) {
console.log('error from reading stream ' + err.toString());
res.end(err);
});
},
_allowCrossDomain: function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Seahorse-version', '0.1.0');
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.send(200);
}
else {
next();
}
}
};
global.utils = utils;
})(this);
(function(global, utils){
'use strict';
var util = require('util'),
path = require('path'),
fs = require('fs');
var routes = {
config: [],
getFilesizeInBytes: function(filename) {
var stats = fs.statSync(filename);
var fileSizeInBytes = stats.size;
return fileSizeInBytes;
},
checkConfig: function(config) {
try
{
var json = JSON.stringify(config);
if( false === (config instanceof Array) ) {
throw "object is not an array";
}
config.forEach(function(element, index, array) {
if( (typeof element.httpRequest === 'undefined') || (typeof element.httpResponse === 'undefined')){
throw "["+index+"] httpResponse or httpRequest missing";
}
if ((typeof element.httpRequest.method === 'undefined') || (typeof element.httpRequest.path === 'undefined')) {
throw "["+index+"] method or path is missing in httpRequest key";
}
if (typeof element.httpResponse.statusCode === 'undefined') {
throw "["+index+"] statusCode is missing in httpResponse key";
}
if ( ( element.httpRequest.method.toUpperCase() === 'GET' ) &&
( element.httpResponse.statusCode != 404 ) &&
( typeof element.httpResponse.body === 'undefined' ) &&
( typeof element.httpResponse.file === 'undefined' ) &&
( typeof element.httpResponse.static === 'undefined' ) ) {
throw "["+index+"] body, file or static are missing in httpResponse key (GET "+element.httpRequest.path+")";
}
});
}
catch(e)
{
if( utils._debug ) {
util.log("[server] input file is not a valid json config file, " + e);
}
return false;
}
return true;
},
setConfig: function(config, app) {
if(this.checkConfig(config)) {
this.config = config;
return true;
}
return false;
},
updateConfig: function(config, app) {
var that = this;
if(this.checkConfig(config)) {
config.forEach(function(element1, index1, array) {
var match = that.config.every(function(element2, index2, array){
if( ( element2.httpRequest.path === element1.httpRequest.path ) &&
( element2.httpRequest.method === element1.httpRequest.method ) &&
( element2.httpRequest.query === element1.httpRequest.query ) ) {
// update the current config element with these new properties
// todo: check this method is correct (element2 will keep a reference to element1)
element2.httpResponse = element1.httpResponse;
return false;
}
else {
return true;
}
});
if( match === true ) {
// add this element to the current config
that.config.push(element1);
}
});
return true;
}
return false;
},
getConfig: function() {
return this.config;
},
_matchPath: function(element, req) {
if ( element.httpRequest.method.toUpperCase() !== req.method.toUpperCase() ) {
return false;
}
if (/^regexp:/.test(element.httpRequest.path)) {
var r = new RegExp(element.httpRequest.path.split(":")[1]);
if( r.test(req.params[0]) !== true ) {
return false;
}
}
else {
// remove trailing slash
if( element.httpRequest.path.replace(/\/$/, '') !== req.params[0].replace(/\/$/, '') ) {
return false;
}
}
return true;
},
all: function(req, res) {
var matchingResponse = {};
var that = this;
// is there at least one element in confg that match with request ?
var match = this.config.some(function(element, index, array) {
if( that._matchPath(element, req) ) {
if( typeof element.httpRequest.query !== 'undefined' ) {
// do all query parameters match with config ?
for (var queryKey in element.httpRequest.query ) {
if( typeof req.query[queryKey] === 'undefined' ) {
return false;
}
else if( element.httpRequest.query[queryKey].toString() !== req.query[queryKey].toString() ) {
return false;
}
}
matchingResponse = element;
return true;
}
matchingResponse = element;
return true;
}
return false;
});
if( match ) {
setTimeout(function() {
// get headers
if( typeof matchingResponse.httpResponse.headers !== 'undefined' ) {
matchingResponse.httpResponse.headers.forEach(function(element, index, array) {
if( element.name && element.value ) {
res.setHeader(element.name, element.value);
}
});
}
// set status code
if( typeof matchingResponse.httpResponse.statusCode !== 'undefined' ) {
res.status(matchingResponse.httpResponse.statusCode);
}
else {
// is this branch really usefull ?
res.status(200);
}
if( typeof matchingResponse.httpResponse.body !== 'undefined') {
// res.setHeader("Content-Length", matchingResponse.httpResponse.body.length);
res.send(matchingResponse.httpResponse.body);
}
else {
var filename;
if( typeof matchingResponse.httpResponse.file !== 'undefined') {
filename = matchingResponse.httpResponse.file;
}
else if( typeof matchingResponse.httpResponse.static !== 'undefined') {
filename = matchingResponse.httpResponse.static+req.originalUrl;
}
if( typeof filename !== 'undefined') {
// convert relative path in absolute
try {
if( path.resolve(filename)!==filename) {
filename = path.normalize(process.cwd()+'/'+filename);
}
res.setHeader("Content-Length", that.getFilesizeInBytes(filename));
utils._sendfile(filename, res);
}
catch(e) {
var notFound="<html>File '+filename+' not found</html>";
res.setHeader("Content-Type", "text/html; charset=UTF-8");
res.setHeader("Content-Length", notFound.length);
res.send(notFound, 404);
}
}
else {
res.send("");
}
}
}, (typeof matchingResponse.httpResponse.delay === 'undefined')?1:matchingResponse.httpResponse.delay);
}
else {
if( utils._debug ) {
util.log('[warning] request not configured');
}
if(req.method.toUpperCase() === 'HEAD') {
res.status(500);
res.setHeader("Content-Length", 0);
res.send();
}
else {
var notFound="<html>Page not found</html>";
res.setHeader("Content-Type", "text/html; charset=UTF-8");
res.setHeader("Content-Length", notFound.length);
res.send(notFound, 404);
}
}
}
};
global.routes = routes;
})(this, this.utils);
(function(global, utils, routes){
'use strict';
var express = require('express');
var morgan = require('morgan');
var util = require('util');
var proxy = require('express-http-proxy');
var app = express();
var server = {
_server: null,
start: function(config, port) {
if( utils._cors ) app.use(utils._allowCrossDomain);
app.use(express.json()); // to support JSON-encoded bodies
app.use(express.urlencoded()); // to support URL-encoded bodies
if( utils._logs ) app.use(morgan('combined'));
// http://127.0.0.1:3000/proxy?originalUrl=http://webapp.local/operator
// -> host = webapp.local
// -> path = /operator
if( utils._proxy ) app.use('/proxy', proxy( function(req){
var url = require('url');
var host = url.parse(req.url.split('originalUrl=')[1]).host;
// return (host?host:url.parse(req.headers.referer).host);
return (host?host:'192.168.1.6');
},{
forwardPath: function(req, res) {
var url = require('url');
return url.parse(url.parse(req.url).query.split('originalUrl=')[1]).path;
},
decorateRequest: function(req) {
console.log("[proxy] " + req.method + " - " + req.hostname + " - " + req.path);
return req;
}
}));
util.log("[server] start seahorse server on port " + port + (utils._logs?" with logs":"") + (utils._proxy?" with proxy activated":"")+ (utils._cors?" (CORS are on)":" (CORS are off)") );
var sseClients = [];
app.get("/stream", function(req, res) {
req.socket.setTimeout(Number.MAX_VALUE);
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// todo, do not add same client multiple times
sseClients.push(res);
util.log("[SSE] new client registered");
res.write('\n');
});
app.post('/_rate/:bps', function(req, res) {
utils._setRate(req.params.bps);
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.send(JSON.stringify({bps: utils._getRate()}));
});
app.get('/_rate', function(req, res) {
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.send(JSON.stringify({bps: utils._getRate()}), 200);
});
app.post('/stream/:event_name', function(req, res) {
var data = "";
try {
data = JSON.stringify(req.body);
}
catch(e) {
data = "ERROR";
}
var id = (new Date()).toLocaleTimeString();
sseClients.forEach(function(element, index, array) {
element.write('id: ' + id + '\n');
element.write("event: " + req.params.event_name + '\n');
// extra newline is not an error
element.write("data: " + data + '\n\n');
});
res.send(200);
});
// permanent route for current configuration reading
app.get("/_config", function(req, res) {
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.send(JSON.stringify(routes.getConfig()), 200);
});
// route for setting a new configuration (erase the previous one)
app.post("/_config", function(req, res) {
var newConfig = req.body;
routes.setConfig(newConfig, app);
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.send(JSON.stringify(routes.getConfig()));
});
// route for updating the current configuration (update the previous one with the new keys)
app.put("/_config", function(req, res) {
var newConfig = req.body;
routes.updateConfig(newConfig, app);
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.send(JSON.stringify(routes.getConfig()), 200);
});
// set initial config
if( typeof config !== 'undefined') {
routes.setConfig(config, app);
}
else {
throw "initial config is undefined";
}
// mock routes
app.all("*", function(req, res) {
if( utils._debug ) {
util.log('[request] ' + req.method + ' ' + req.originalUrl + '\t('+ ((typeof req.headers['user-agent'] !== 'undefined')?req.headers['user-agent']:"unknown") +')');
util.log('[request] [headers] ' + JSON.stringify(req.headers));
}
routes.all(req, res);
});
var self = this;
process.on( "SIGINT", function() {
self.stop();
} );
// start listening
this._server = app.listen(port);
},
stop: function() {
util.log("[server] stop seahorse server");
// todo: ask confirmation
if( this._server !== null ) {
this._server.close();
}
}
};
global.server = server;
})(this, this.utils, this.routes);
;
var should = require('should');
var api = require('hippie');
var routes = this.routes;
var server = this.server;
server.start(null, 3000);
;
var should = require('should');
var routes = this.routes;
describe("[routes.js] ", function(){
var configOk = [
{
"httpRequest" : {
"method" : "get",
"path" : "/foo"
},
"httpResponse" : {
"statusCode" : 200,
"body" : "{\"key\": \"value\"}",
"headers" : [ {
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
},
{
"name": "Content-Type",
"value": "application/json; charset=utf-8"
} ],
"delay": 1
}
}
];
var updateOkSame = [
{
"httpRequest" : {
"method" : "get",
"path" : "/foo"
},
"httpResponse" : {
"statusCode" : 200,
"body" : "{\"key\": \"value\"}",
"headers" : [ {
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
},
{
"name": "Content-Type",
"value": "application/json; charset=utf-8"
} ],
"delay": 1
}
}
];
var updateOkDifferent = [
{
"httpRequest" : {
"method" : "post",
"path" : "/foo"
},
"httpResponse" : {
"statusCode" : 200,
"body" : "{\"key\": \"value\"}",
"headers" : [ {
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
},
{
"name": "Content-Type",
"value": "application/json; charset=utf-8"
} ],
"delay": 1
}
}
];
describe('Test checkConfig method of routes module', function() {
describe('with a config file with is not a json', function() {
it('should returns false', function() {
routes.checkConfig("foo").should.eql(false);
});
});
describe('with a config file with an incorrect syntax (no httpRequest)', function() {
// ugly way for duplicate object, isn't it ?
var configKo = JSON.parse( JSON.stringify( configOk ) );
delete configKo[0].httpRequest;
it('should returns false', function() {
routes.checkConfig(configKo).should.eql(false);
});
});
describe('with a config file with an incorrect syntax (no method)', function() {
// ugly way for duplicate object, isn't it ?
var configKo = JSON.parse( JSON.stringify( configOk ) );
delete configKo[0].httpRequest.method;
it('should returns false', function() {
routes.checkConfig(configKo).should.eql(false);
});
});
describe('with a config file with an incorrect syntax (no path)', function() {
// ugly way for duplicate object, isn't it ?
var configKo = JSON.parse( JSON.stringify( configOk ) );
delete configKo[0].httpRequest.path;
it('should returns false', function() {
routes.checkConfig(configKo).should.eql(false);
});
});
describe('with a config file with an incorrect syntax (no httpResponse)', function() {
// ugly way for duplicate object, isn't it ?
var configKo = JSON.parse( JSON.stringify( configOk ) );
delete configKo[0].httpResponse;
it('should returns false', function() {
routes.checkConfig(configKo).should.eql(false);
});
});
describe('with a config file with an incorrect syntax (no statusCode)', function() {
// ugly way for duplicate object, isn't it ?
var configKo = JSON.parse( JSON.stringify( configOk ) );
delete configKo[0].httpResponse.statusCode;
it('should returns false', function() {
routes.checkConfig(configKo).should.eql(false);
});
});
describe('with a config file with an incorrect syntax (no body nor file)', function() {
// ugly way for duplicate object, isn't it ?
var configKo = JSON.parse( JSON.stringify( configOk ) );
delete configKo[0].httpResponse.body;
it('should returns false', function() {
routes.checkConfig(configKo).should.eql(false);
});
});
describe('with a config file with a file key instead of body', function() {
// ugly way for duplicate object, isn't it ?
var configOk2 = JSON.parse( JSON.stringify( configOk ) );
delete configOk2[0].httpResponse.body;
configOk2[0].httpResponse.file = "http://www.google.com";
it('should returns true', function() {
routes.checkConfig(configOk2).should.eql(true);
});
});
describe('with a config file with correct syntax', function() {
it('should returns true', function() {
routes.checkConfig(configOk).should.eql(true);
});
});
});
describe('Test setConfig method of routes module', function() {
describe('with an incorrect config file', function() {
it('should returns false', function(done) {
routes.config = {};
routes.setConfig("foo").should.eql(false);
done();
});
it('should not modify config property', function(done) {
routes.config.should.be.empty;
done();
});
});
describe('with an correct config file', function() {
it('should returns true', function(done) {
routes.config = {};
routes.setConfig(configOk).should.eql(true);
done();
});
it('should modify config property', function(done) {
routes.config.length.should.eql(1);
routes.config[0].should.have.properties('httpRequest', 'httpResponse');
routes.config[0].httpRequest.should.have.properties('method', 'path');
routes.config[0].httpResponse.should.have.properties('statusCode', 'body', 'headers', 'delay');
done();
});
});
});
describe('Test getConfig method of routes module', function() {
it('should returns the current config', function(done) {
routes.config = JSON.parse( JSON.stringify( configOk ) );
routes.getConfig().should.eql(configOk);
done();
});
});
describe('Test updateConfig method of routes module', function() {
describe('with an incorrect config file', function() {
it('should returns false', function(done) {
routes.config = JSON.parse( JSON.stringify( configOk ) );
routes.updateConfig("foo").should.eql(false);
done();
});
it('should not modify config property', function(done) {
routes.config.should.eql(configOk);
done();
});
});
describe('with an correct config file but with same method and path', function() {
it('should returns true', function(done) {
routes.config = JSON.parse( JSON.stringify( configOk ) );
routes.updateConfig(updateOkSame).should.eql(true);
done();
});
it('should not modify config', function(done) {
routes.config.length.should.eql(1);
routes.config.should.eql(configOk);
done();
});
});
describe('with an correct config file and diffrent method or path', function() {
it('should returns true', function(done) {
routes.config = JSON.parse( JSON.stringify( configOk ) );
routes.updateConfig(updateOkDifferent).should.eql(true);
done();
});
it('should modify config', function(done) {
routes.config.length.should.eql(2);
routes.config[0].httpRequest.method.should.eql('get');
routes.config[1].httpRequest.method.should.eql('post');
done();
});
});
});
var staticConfig = [
{
"httpRequest" : {
"method" : "get",
"path" : "regexp:^\/.*\.json$"
},
"httpResponse" : {
"statusCode" : 200,
"static" : ".",
"headers" : [ {
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
},
{
"name": "Content-Type",
"value": "application/json; charset=utf-8"
} ]
}
}
];
describe('Test static file serving of routes module', function() {
describe('get a resource', function() {
beforeEach(function(){
routes.setConfig(staticConfig);
});
it('should returns a 200 status code and an empty array', function(done) {
api()
.json()
.base('http://localhost:3000')
.get('/specs/empty.json')
.expectStatus(200)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody([])
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should returns a 200 status code and an simple array', function(done) {
api()
.json()
.base('http://localhost:3000')
.get('/specs/array.json')
.expectStatus(200)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody([1, 2, 3])
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should returns a 404 status code for an unknown resource', function(done) {
api()
.base('http://localhost:3000')
.get('/specs/unknown.json')
.expectStatus(404)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
});
});
var fileConfig = [
{
"httpRequest" : {
"method" : "get",
"path" : "/array.json"
},
"httpResponse" : {
"statusCode" : 200,
"file" : "specs/array.json",
"headers" : [ {
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
},
{
"name": "Content-Type",
"value": "application/json; charset=utf-8"
} ]
}
}
];
describe('Test direct file serving of routes module', function() {
describe('get a resource', function() {
beforeEach(function(){
routes.setConfig(fileConfig);
});
it('should returns a 200 status code and an simple array', function(done) {
api()
.json()
.base('http://localhost:3000')
.get('/array.json')
.expectStatus(200)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectHeader('Content-length', '9')
.expectBody([1, 2, 3])
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should returns a 404 status code for an unknown resource', function(done) {
api()
.base('http://localhost:3000')
.get('/unknown.json')
.expectStatus(404)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
});
});
});
;
describe("[server.js] ", function(){
var config = [
{
"httpRequest" : {
"method" : "get",
"path" : "/foo"
},
"httpResponse" : {
"statusCode" : 200,
"body" : "{\"key\": \"value\"}",
"headers" : [ {
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
},
{
"name": "Content-Type",
"value": "application/json; charset=utf-8"
} ],
"delay": 1
}
}
];
var otherConfig = [
{
"httpRequest" : {
"method" : "post",
"path" : "/bar"
},
"httpResponse" : {
"statusCode" : 404,
"delay": 1
}
}
];
describe('Test get /_config server route', function() {
beforeEach(function(){
routes.setConfig(config);
});
it('should returns config object', function(done) {
api()
.json()
.base('http://localhost:3000')
.get('/_config')
.expectStatus(200)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody(config)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
});
describe('Test post /_config server route', function() {
beforeEach(function(){
routes.setConfig(config);
});
it('should returns new config when called with a correct config file', function(done) {
api()
.json()
.base('http://localhost:3000')
.post('/_config')
.send(otherConfig)
.expectStatus(200)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody(otherConfig)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should returns initial config when called with an incorrect config file', function(done) {
api()
.json()
.base('http://localhost:3000')
.post('/_config')
.send(null)
.expectStatus(200)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody(config)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
});
describe('Test put /_config server route', function() {
beforeEach(function(){
routes.setConfig(config);
});
it('should returns new config when called with a correct config file', function(done) {
api()
.json()
.base('http://localhost:3000')
.put('/_config')
.send(otherConfig)
.expectStatus(200)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody(config.concat(otherConfig))
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should returns initial config when called with an incorrect config file', function(done) {
api()
.json()
.base('http://localhost:3000')
.put('/_config')
.send(null)
.expectStatus(200)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody(config)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
});
});
;
describe("[seahorse.js] ", function(){
this.timeout(50);
var config = [
{
"httpRequest" : {
"method" : "get",
"path" : "/foo/"
},
"httpResponse" : {
"statusCode" : 200,
"body" : "{\"key\": \"value\"}",
"headers" : [
{
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
},
{
"name": "Content-Type",
"value": "application/json; charset=utf-8"
}
],
"delay": 1
}
},
{
"httpRequest" : {
"method" : "post",
"path" : "/foo"
},
"httpResponse" : {
"statusCode" : 201,
"delay": 1
}
},
{
"httpRequest" : {
"method" : "put",
"path" : "/foo"
},
"httpResponse" : {
"statusCode" : 202,
"delay": 1
}
},
{
"httpRequest" : {
"method" : "delete",
"path" : "/foo/"
},
"httpResponse" : {
"statusCode" : 203,
"delay": 3000
}
},
{
"httpRequest" : {
"method" : "get",
"path" : "/fooquery",
"query": {
"Content-Type": "application/json",
"key": "value"
}
},
"httpResponse" : {
"statusCode" : 200,
"body" : "{\"key\": \"value\"}",
"headers" : [
{
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
},
{
"name": "Content-Type",
"value": "application/json"
}
],
"delay": 1
}
},
{
"httpRequest" : {
"method" : "get",
"path" : "/fooquery",
"query": {
"Content-Type": "application/html"
}
},
"httpResponse" : {
"statusCode" : 200,
"body" : "<html>Hello</html>",
"headers" : [
{
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
},
{
"name": "Content-Type",
"value": "application/html"
}
],
"delay": 1
}
}
];
beforeEach(function(){
routes.setConfig(config);
});
describe('Test get /_config server route', function() {
it('should returns config object', function(done) {
api()
.json()
.base('http://localhost:3000')
.get('/_config')
.expectStatus(200)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody(config)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
});
describe('Test status code', function() {
it('should be 404 when request get /foobar', function(done) {
api()
.base('http://localhost:3000')
.get('/foobar')
.expectStatus(404)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 200 when request get /foo', function(done) {
api()
.json()
.base('http://localhost:3000')
.get('/foo')
.expectStatus(200)
.expectHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody({"key": "value"})
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 200 when request get /foo/', function(done) {
api()
.json()
.base('http://localhost:3000')
.get('/foo/')
.expectStatus(200)
.expectHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody({"key": "value"})
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 201 when request post /foo', function(done) {
api()
.json()
.base('http://localhost:3000')
.post('/foo')
.expectStatus(201)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 201 when request post /foo/', function(done) {
api()
.json()
.base('http://localhost:3000')
.post('/foo/')
.expectStatus(201)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 202 when request put /foo', function(done) {
api()
.json()
.base('http://localhost:3000')
.put('/foo')
.expectStatus(202)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 202 when request put /foo/', function(done) {
api()
.json()
.base('http://localhost:3000')
.put('/foo/')
.expectStatus(202)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 203 when request delete /foo', function(done) {
this.timeout(5000);
api()
.json()
.url('http://localhost:3000/foo')
.method('DELETE')
.expectStatus(203)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 203 when request delete /foo/', function(done) {
this.timeout(5000);
api()
.json()
.url('http://localhost:3000/foo/')
.method('DELETE')
.expectStatus(203)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
});
describe('Test queryparameters', function() {
it('should be 404 when request get /fooquery without parameters', function(done) {
api()
.base('http://localhost:3000')
.get('/fooquery')
.expectStatus(404)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 404 when request get /fooquery without all parameters', function(done) {
api()
.base('http://localhost:3000')
.get('/fooquery?key=value')
.expectStatus(404)
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 200 when request get /fooquery with all parameters', function(done) {
api()
.json()
.base('http://localhost:3000')
.get('/fooquery?key=value&Content-Type=application/json')
.expectStatus(200)
.expectHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectBody({"key": "value"})
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
it('should be 200 when request get /fooquery with all parameters', function(done) {
api()
.base('http://localhost:3000')
.get('/fooquery?Content-Type=application/html')
.expectStatus(200)
.expectHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
.expectHeader('Content-Type', 'application/html; charset=utf-8')
.expectBody("<html>Hello</html>")
.end(function(err, res, body) {
if (err) throw err;
done();
});
});
});
});