Unexpected-express

Example
Assert that a particular request specified in the request property to
myMiddleware results in a response whose values match those in the properties
listed in the response property:
var expect = require('unexpected')
.clone()
.installPlugin(require('unexpected-express'));
function myMiddleware(req, res, next) {
var contentType = req.headers['accept'] || 'text/plain';
if (contentType !== 'text/plain' && contentType !== 'text/html') {
return res.status(400).end();
}
res.type(contentType);
var body = 'Here goes ' + req.url + ' as ' + contentType;
if (contentType === 'text/html') {
body =
'<html>' + body.replace(/&/g, '&').replace(/</g, '<') + '</html>';
}
res.setHeader('Date', 'Sat, 12 Mar 2016 22:56:04 GMT');
res.send(body);
}
return expect(express().use(myMiddleware), 'to yield exchange', {
request: {
url: '/blah',
headers: {
Accept: 'text/plain',
},
},
response: {
statusCode: 200,
headers: {
'Content-Type': 'text/plain; charset=utf-8',
},
body: 'Here goes /blah as text/plain',
},
});
Extended assertions
Sometimes you may want to make additional assertions on the response after the
primary comparisons are completed by 'to yield exchange'. This is possible by
attaching another function to the promise that is returned and executing further
assertions.
For example, imagine a middleware that generates a timestamp on returned requests
and while you may not know what the value will be, you wish to assert its presence:
function secondMiddleware(req, res, next) {
res.type('json');
var body = {};
body.timestamp = Date.now();
res.send(body);
}
return expect(express().use(secondMiddleware), 'to yield exchange', {
request: 'GET /other',
response: 200,
}).then(function (context) {
// retrieve the response body
var body = context.httpResponse.body;
expect(body.timestamp, 'to be defined');
});
The context object provided to the then()
callback will be provided a context
object exposes the following properties on which assertions can be made:
- httpRequest
- httpResponse
- res
- req
Extensive testing
If you're going to test a piece of middleware extensively, you can create your
own custom assertion around that to increase DRYness and put the request
properties into the subject's spot:
expect.addAssertion(
'<object|string> to yield a response of <object|number>',
function (expect, subject, value) {
return expect(express().use(myMiddleware), 'to yield exchange', {
request: subject,
response: value,
});
}
);
return expect('/barf', 'to yield a response of', {
body: 'Here goes /barf as text/plain',
});
return expect(
{
url: '/quux',
headers: {
Accept: 'text/html',
},
},
'to yield a response of',
{
body: '<html>Here goes /quux as text/html</html>',
}
);
// should entitify less than and ampersand chars in text/html
return expect(
{
url: '/<h&ey<',
headers: {
Accept: 'text/html',
},
},
'to yield a response of',
{
body: '<html>Here goes /<h&ey< as text/html</html>',
}
);
// should not entitify in text/plain
return expect('/<hey', 'to yield a response of', {
body: 'Here goes /<hey as text/plain',
});
// should return a 400 if asked for an unsupported Content-Type
return expect(
{
url: '/something',
headers: {
Accept: 'text/calendar',
},
},
'to yield a response of',
400
);
To read more about adding custom assertions please see the unexpected
documentation here.
Testing POST requests
There are three commonly used way to POST content to a backend: JSON POST-request (Content-Type = application/json
), HTML form POST-request (Content-Type = application/x-www-form-urlencoded
) and multipart POST-request typically used for file uploads (Content-Type = multipart/form-data
).
JSON
To test JSON POST-requests you can use the request
object's data
property:
return expect(express().use(myMiddleware), 'to yield exchange', {
request: {
url: 'POST /api/',
data: {
title: 'Hello World',
},
},
response: 200,
});
HTML form POST
To test HTML form POST-requests you can use the request
objects form
-property:
return expect(express().use(myMiddleware), 'to yield exchange', {
request: {
url: 'POST /api/',
form: {
title: 'Hello World',
},
},
response: 200,
});
Multipart (file upload) form POST
To test multipart form POST-requests you can use the request
objects formData
-property:
return expect(express().use(myMiddleware), 'to yield exchange', {
request: {
url: 'POST /api/',
formData: {
title: 'Hello World',
attachment: {
value: Buffer.from([0x00, 0x01]),
contentType: 'foo/bar',
filename: 'blabla',
},
},
},
response: 200,
});
Reporting
You'll get a nice diff when expectations aren't met:
return expect('/baz', 'to yield a response of', {
statusCode: 404,
body: 'I could not find /baz',
});
expected '/baz'
to yield a response of { statusCode: 404, body: 'I could not find /baz' }
HTTP/1.1 200 OK should be 404 Not Found
HTTP/1.1 200 OK
HTTP/1.1 404 Not Found
X-Powered-By: Express
Content-Type: text/plain; charset=utf-8
Date: Sat, 12 Mar 2016 22:56:04 GMT
Content-Length: 28
ETag: W/"1c-HFUAMbnVgCT4McocftsoE3lehW4"
Connection: keep-alive
Here goes /baz as text/plain
I could not find /baz
Additional features:
- Normalizes header names so you don't need to use the ugly lower-case form in the assertions
- The expected response bodies can be specified as either strings, objects (implies JSON), or Buffer instances
- Request bodies can be provided as either strings, objects (implies JSON), Buffer instances, or streams.
- Request body streams that are instances of https://github.com/felixge/node-form-data are special cased to implicitly set the
Content-Type
header correctly.
Releases
Changelog
License
Unexpected-express is licensed under a standard 3-clause BSD license
-- see the LICENSE
file for details.