I am testing a Node.js API with supertest, and I cannot explain why the res.body
object superset returns is empty. The data shows up in the res.text
object, but not res.body
, any idea how to fix this?
I am using Express and body-parser
:
app.use(bodyParser.json());
app.use(bodyParser.json({ type: jsonMimeType }));
app.use(bodyParser.urlencoded({ extended: true }));
Here is the API method I am testing:
app.get(apiPath + '/menu', function(req, res) {
var expiration = getExpiration();
res.set({
'Content-Type': jsonMimeType,
'Content-Length': jsonTestData.length,
'Last-Modified': new Date(),
'Expires': expiration,
'ETag': null
});
res.json({ items: jsonTestData });
}
Here are the tests I am executing against this API method:
describe('GET /menu', function() {
describe('HTTP headers', function() {
it('responds with the right MIME type', function(done) {
request(app)
.get(apiPath + '/menu')
.set('Accept', 'application/vnd.burgers.api+json')
.expect('Content-Type', 'application/vnd.burgers.api+json; charset=utf-8')
.expect(200, done);
});
it('responds with the right expiration date', function(done) {
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(0,0,0,0);
request(app)
.get(apiPath + '/menu')
.set('Accept', 'application/vnd.burgers.api+json; charset=utf-8')
.expect('Expires', tomorrow.toUTCString())
.expect(200, done);
});
it('responds with menu items', function(done) {
request(app)
.get(apiPath + '/menu')
.set('Accept', 'application/vnd.burgers.api+json; charset=utf-8')
.expect(200)
.expect(function (res) {
console.log(res);
res.body.items.length.should.be.above(0);
})
.end(done);
});
});
});
The failure I receive:
1) GET /menu HTTP headers responds with menu items:
TypeError: Cannot read property 'length' of undefined
at /Users/brian/Development/demos/burgers/menu/test/MenuApiTest.js:42:25
at Test.assert (/Users/brian/Development/demos/burgers/menu/node_modules/supertest/lib/test.js:213:13)
at Server.assert (/Users/brian/Development/demos/burgers/menu/node_modules/supertest/lib/test.js:132:12)
at Server.g (events.js:180:16)
at Server.emit (events.js:92:17)
at net.js:1276:10
at process._tickDomainCallback (node.js:463:13)
And finally, here is an excerpt of the result of console.log(res)
:
...
text: '{"items":[{"id":"1","name":"cheeseburger","price":3},{"id":"2","name":"hamburger","price":2.5},{"id":"3","name":"veggie burger","price":3},{"id":"4","name":"large fries","price":2},{"id":"5","name":"medium fries","price":1.5},{"id":"6","name":"small fries","price":1},{"id":"7","name":"large drink","price":2.5},{"id":"8","name":"medium drink","price":2},{"id":"9","name":"small drink","price":1}]}',
body: {},
...
add
this will accept all json content types :-)
My problem was that the
.set()
method set the request headers, whereas.send()
will set the request body with the json data you specify.The fix:
This is old, but it helped me so thought I might share some knowledge.
Working off of mattr example, I found that that information was actually in the res.text, not the res.body.
I ended up adding some special handling for:
Based on the following test you are expecting 'application/vnd.burgers.api+json; charset=utf-8' as the Content-Type:
This express route also shows you setting the header to some custom value, jsonMimeType:
If this is the case, supertest isnt going to parse that JSON automatically for you. The content-type header must start with the string 'application/json'. If you cant make that happen, then you will have to use the JSON.parse function yourself to convert that text string to an object.
supertest uses this file to determine if you are sending json or not. Under the hood, supertest actually starts up your express server, makes the one request via HTTP, and quickly shuts it down. After that HTTP handoff, the client side (which is basically superagent) of that HTTP request doesnt know anything about your server configuration with regard to 'application/vnd.burgers.api+json; charset=utf-8'. All it know is what its told via headers, in this case, content-type.
Also, I did try your custom header on my machine and I also got an empty body.
Edit: updated table link as stated in the comments