Skip to content

Commit

Permalink
Some basic improvements to responder and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mde committed Jan 25, 2014
1 parent 092afe1 commit 975141c
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 59 deletions.
17 changes: 8 additions & 9 deletions lib/controller/responder/strategies/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* strategy for now.
*/
var utils = require('utilities')
, model = require('model')
, getCreateSuccessLocation = function () {
hostname = (geddy && geddy.config && geddy.config.fullHostname) || '';
return hostname;
Expand All @@ -30,7 +31,7 @@ var utils = require('utilities')
}

// Determine if `content` is a model object
if (typeof content === 'object' && content.type && content.toObj) {
if (content instanceof model.ModelBase) {
// Respond in the style {attr: val, attr2: val...}
response = content.toObj();
response.id = content.id;
Expand All @@ -47,14 +48,12 @@ var utils = require('utilities')
}
// Determine if `content` is a collection of models
else if (content instanceof Array) {
response = [];

for(var i=0, ii=content.length; i<ii; i++) {
response[i] = content[i].toObj();
response[i].id = content[i].id;
response[i].type = content[i].type;
}

response = content.map(function (item) {
var contentItem = item.toObj();
contentItem.id = item.id;
contentItem.type = item.type;
return contentItem;
});
}
else if (content instanceof Error || (content.message && content.stack)) {
// Format error for API-display
Expand Down
138 changes: 88 additions & 50 deletions test/controllers/controller_respond.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
var assert = require('assert')
, utils = require('utilities')
, model = require('model')
, Zooby = require('../fixtures/zooby').Zooby
, Responder = require('../../lib/controller/responder').Responder
, Controller = require('../../lib/controller/base_controller').BaseController
, MockRequest
, tests
, createModelInstance = function () {
return {
id: 'mambo-no-5'
, type: 'zooby'
, toObj: function () {
var buf = {};
for(var key in this) {
if(this.hasOwnProperty(key)
&& key !== 'toObj'
&& key !== 'type') {
buf[key] = this[key];
}
}
return buf;
}
}
var zooby = Zooby.create({
title: 'asdf'
, description: 'qwer'
});
zooby.id = 'mambo-no-5';
return zooby;
}
, createController = function () {
var c = new Controller();
Expand All @@ -37,24 +31,25 @@ var assert = require('assert')
return c;
};


var MockRequest = function () {
MockRequest = function () {
this.headers = {
accept: '*/*'
}
};

Zooby = model.register('Zooby', Zooby);

// Just to make sure our lowest level method is working
tests = {
'respond in html, format specified and supported': function (next) {
var c = createController();
c.output = function (statusCode, headers, content) {
assert.equal(200, statusCode);
assert.equal('text/html', headers['Content-Type']);
assert.equal('<div>{"foo":"bar"}</div>', content);
assert.equal('<div>{"zooby":"bar"}</div>', content);
next();
};
c.respond({foo: 'bar'}, {format: 'html'});
c.respond({zooby: 'bar'}, {format: 'html'});
}

, 'respond in html, format in params and supported': function (next) {
Expand All @@ -63,21 +58,21 @@ tests = {
c.output = function (statusCode, headers, content) {
assert.equal(200, statusCode);
assert.equal('text/html', headers['Content-Type']);
assert.equal('<div>{"foo":"bar"}</div>', content);
assert.equal('<div>{"zooby":"bar"}</div>', content);
next();
};
c.respond({foo: 'bar'});
c.respond({zooby: 'bar'});
}

, 'respond in json, format specified and supported': function (next) {
var c = createController();
c.output = function (statusCode, headers, content) {
assert.equal(200, statusCode);
assert.equal('application/json', headers['Content-Type']);
assert.equal('{"foo":"bar"}', content);
assert.equal('{"zooby":"bar"}', content);
next();
};
c.respond({foo: 'bar'}, {format: 'json'});
c.respond({zooby: 'bar'}, {format: 'json'});
}

, 'respond in json, format in params and supported': function (next) {
Expand All @@ -86,10 +81,10 @@ tests = {
c.output = function (statusCode, headers, content) {
assert.equal(200, statusCode);
assert.equal('application/json', headers['Content-Type']);
assert.equal('{"foo":"bar"}', content);
assert.equal('{"zooby":"bar"}', content);
next();
};
c.respond({foo: 'bar'});
c.respond({zooby: 'bar'});
}

, 'respond in js (JSONP), format specified and supported': function (next) {
Expand All @@ -98,10 +93,10 @@ tests = {
c.output = function (statusCode, headers, content) {
assert.equal(200, statusCode);
assert.equal('application/javascript', headers['Content-Type']);
assert.equal('zoobyasdf({"foo":"bar"});', content);
assert.equal('zoobyasdf({"zooby":"bar"});', content);
next();
};
c.respond({foo: 'bar'}, {format: 'js'});
c.respond({zooby: 'bar'}, {format: 'js'});
}

, 'respond in js (JSONP), format in params and supported': function (next) {
Expand All @@ -111,10 +106,10 @@ tests = {
c.output = function (statusCode, headers, content) {
assert.equal(200, statusCode);
assert.equal('application/javascript', headers['Content-Type']);
assert.equal('zoobyasdf({"foo":"bar"});', content);
assert.equal('zoobyasdf({"zooby":"bar"});', content);
next();
};
c.respond({foo: 'bar'});
c.respond({zooby: 'bar'});
}

, 'respond with available built-in format even if controller \
Expand All @@ -124,27 +119,27 @@ doesn\'t explicitly explicitly support it': function (next) {
assert.equal(200, statusCode);
assert.equal('application/xml', headers['Content-Type']);
assert.equal('<?xml version="1.0" encoding="UTF-8"?>\n' +
'<object>\n <foo>bar</foo>\n</object>\n', content);
'<object>\n <zooby>bar</zooby>\n</object>\n', content);
next();
};
c.respond({foo: 'bar'}, {format: 'xml'});
c.respond({zooby: 'bar'}, {format: 'xml'});
}

, 'respond with first supported format if no format specified': function (next) {
var c = createController();
c.output = function (statusCode, headers, content) {
assert.equal(200, statusCode);
assert.equal('text/html', headers['Content-Type']);
assert.equal('<div>{"foo":"bar"}</div>', content);
assert.equal('<div>{"zooby":"bar"}</div>', content);
next();
};
c.respond({foo: 'bar'});
c.respond({zooby: 'bar'});
}

, 'throw when unsupported format requested': function (next) {
var c = createController();
assert.throws(function () {
c.respond({foo: 'bar'}, {format: 'frang'});
c.respond({zooby: 'bar'}, {format: 'frang'});
});
next();
}
Expand All @@ -154,10 +149,40 @@ doesn\'t explicitly explicitly support it': function (next) {
c.output = function (statusCode, headers, content) {
assert.equal(222, statusCode);
assert.equal('text/html', headers['Content-Type']);
assert.equal('<div>{"foo":"bar"}</div>', content);
assert.equal('<div>{"zooby":"bar"}</div>', content);
next();
};
c.respond({zooby: 'bar'}, {statusCode: 222});
}

, 'respond, ad-hoc model properties not preserved': function (next) {
var c = createController()
, inst = createModelInstance();
inst.zerp = 'derp';
c.output = function (statusCode, headers, content) {
var item = JSON.parse(content);
assert.ok(!item.zerp);
next();
};
c.respond(inst, {format: 'json'});
}

, 'respond, ad-hoc model properties preserved': function (next) {
var c = createController()
, inst = createModelInstance()
, origToJSON = inst.toJSON;
inst.zerp = 'derp';
inst.toJSON = function () {
var ret = origToJSON.call(this);
ret.zerp = this.zerp;
return ret;
};
c.output = function (statusCode, headers, content) {
var item = JSON.parse(content);
assert.ok(item.zerp);
next();
};
c.respond({foo: 'bar'}, {statusCode: 222});
c.respond(inst, {format: 'json'});
}

// respondTo tests, mid-level API
Expand Down Expand Up @@ -217,10 +242,12 @@ but not explicitly supported on controller': function (next) {
c.params.format = 'json';
c.params.action = 'create';
c.output = function (statusCode, headers, content) {
var item = JSON.parse(content);
assert.equal(201, statusCode);
assert.equal('application/json', headers['Content-Type']);
assert.equal('/zoobies/mambo-no-5', headers['Location']);
assert.equal('{"id":"mambo-no-5","type":"zooby"}', content);
assert.equal('mambo-no-5', item.id);
assert.equal('Zooby', item.type);
next();
};
c.respondWith(createModelInstance());
Expand Down Expand Up @@ -248,10 +275,12 @@ but not explicitly supported on controller': function (next) {
c.params.format = 'json';
c.params.action = 'create';
c.output = function (statusCode, headers, content) {
var item = JSON.parse(content);
assert.equal(400, statusCode);
assert.equal('application/json', headers['Content-Type']);
assert.equal('{"id":"mambo-no-5","errors":{"poop":"asdf"},"type":"zooby"}',
content);
assert.equal('mambo-no-5', item.id);
assert.equal('asdf', item.errors.poop);
assert.equal('Zooby', item.type);
next();
};
inst = createModelInstance();
Expand All @@ -277,10 +306,11 @@ but not explicitly supported on controller': function (next) {
c.params.format = 'json';
c.params.action = 'remove';
c.output = function (statusCode, headers, content) {
var item = JSON.parse(content);
assert.equal(200, statusCode);
assert.equal('application/json', headers['Content-Type']);
assert.equal('{"id":"mambo-no-5","type":"zooby"}',
content);
assert.equal('mambo-no-5', item.id);
assert.equal('Zooby', item.type);
next();
};
c.respondWith(createModelInstance());
Expand Down Expand Up @@ -308,10 +338,12 @@ but not explicitly supported on controller': function (next) {
c.params.format = 'json';
c.params.action = 'remove';
c.output = function (statusCode, headers, content) {
var item = JSON.parse(content);
assert.equal(400, statusCode);
assert.equal('application/json', headers['Content-Type']);
assert.equal('{"id":"mambo-no-5","errors":{"derp":"zerp"},"type":"zooby"}',
content);
assert.equal('mambo-no-5', item.id);
assert.equal('zerp', item.errors.derp);
assert.equal('Zooby', item.type);
next();
};
inst = createModelInstance();
Expand All @@ -337,10 +369,11 @@ but not explicitly supported on controller': function (next) {
c.params.format = 'json';
c.params.action = 'update';
c.output = function (statusCode, headers, content) {
var item = JSON.parse(content);
assert.equal(200, statusCode);
assert.equal('application/json', headers['Content-Type']);
assert.equal('{"id":"mambo-no-5","type":"zooby"}',
content);
assert.equal('mambo-no-5', item.id);
assert.equal('Zooby', item.type);
next();
};
c.respondWith(createModelInstance());
Expand Down Expand Up @@ -368,10 +401,12 @@ but not explicitly supported on controller': function (next) {
c.params.format = 'json';
c.params.action = 'update';
c.output = function (statusCode, headers, content) {
var item = JSON.parse(content);
assert.equal(400, statusCode);
assert.equal('application/json', headers['Content-Type']);
assert.equal('{"id":"mambo-no-5","errors":{"derp":"zerp"},"type":"zooby"}',
content);
assert.equal('mambo-no-5', item.id);
assert.equal('zerp', item.errors.derp);
assert.equal('Zooby', item.type);
next();
};
inst = createModelInstance();
Expand All @@ -388,8 +423,9 @@ but not explicitly supported on controller': function (next) {
c.output = function (statusCode, headers, content) {
assert.equal(200, statusCode);
assert.equal('text/html', headers['Content-Type']);
assert.equal('<div>{"params":{"format":"html","action":"show"},' +
'"zooby":{"id":"mambo-no-5"}}</div>', content);
assert.ok(content.indexOf('<div>') > -1);
assert.ok(content.indexOf('</div>') > -1);
assert.ok(content.indexOf('mambo-no-5') > -1);
next();
};
c.respondWith(createModelInstance());
Expand All @@ -400,9 +436,11 @@ but not explicitly supported on controller': function (next) {
c.params.format = 'json';
c.params.action = 'show';
c.output = function (statusCode, headers, content) {
var item = JSON.parse(content);
assert.equal(200, statusCode);
assert.equal('application/json', headers['Content-Type']);
assert.equal('{"id":"mambo-no-5","type":"zooby"}', content);
assert.equal('mambo-no-5', item.id);
assert.equal('Zooby', item.type);
next();
};
c.respondWith(createModelInstance());
Expand Down
15 changes: 15 additions & 0 deletions test/fixtures/zooby.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var Zooby = function () {
this.property('title', 'string');
this.property('description', 'text');
this.property('body', 'text');
};

Zooby.prototype.someMethod = function () {
};

module.exports.Zooby = Zooby;





0 comments on commit 975141c

Please sign in to comment.