archived-servertest
archived-servertest copied to clipboard
A simple HTTP server testing tool
servertest
A simple HTTP server testing tool
Why?
servertest exists because supertest does way too much and gets in the way when you need to do anything novel (the typical "framework" problem).
servertest doesn't do any assertions for you, you simply hand it an HTTP server and it manages the start / stop lifecycle and makes a request for you, passing you back the results. servertest is built on hyperquest as an HTTP client and supports the same options as hyperquest and will stream if you need to (in and/or out).
Examples
var server = http.createServer(function (req, res) {
res.end('OK')
})
test('simple web server', function (t) {
servertest(server, '/', { encoding: 'utf8' }, function (err, res) {
t.ifError(err, 'no error')
t.equal(res.statusCode, 200, 'correct statusCode')
t.equal(res.body, 'OK', 'correct body content')
t.end()
})
})
Even JSON encoding can be handled for you:
var server = http.createServer(function (req, res) {
res.end(JSON.stringify({ ok: 'mate' }))
})
test('json web server', function (t) {
servertest(server, '/', { encoding: 'json' }, function (err, res) {
t.ifError(err, 'no error')
t.equal(res.statusCode, 200, 'correct statusCode')
t.deepEqual(res.body, { ok: 'mate' }, 'correct body content')
t.end()
})
})
And of course it's streams all the way:
// uppercasing server, post it a string and it'll return
// an uppercased version of it
var server = http.createServer(function (req, res) {
req.pipe(through2(function (chunk, enc, callback) {
callback(null, chunk.toString().toUpperCase())
})).pipe(res)
})
test('duplex uppercasing server', function (t) {
// servertest is a duplex stream when posting data
var serverStream = servertest(server, '/', { method: 'POST' })
// pipe data to the POST request
fs.createReadStream(__filename).pipe(serverStream)
// pipe data from the response
serverStream.pipe(bl(function (err, data) {
t.ifError(err, 'no error')
var expected = fs.readFileSync(__filename, 'utf8').toUpperCase()
t.equal(data.toString(), expected, 'uppercased data')
t.end()
}))
})
Of course this assumes that you have easy access to your http.Server
object in your tests. Normally you will want to expose it on your server directly on your main server start script and not perform the listen()
yourself if it's not being run as the "main":
index.js
module.exports = function () {
return http.createServer(handler)
}
if (require.main === module) {
module.exports().listen(port, function (err) {
console.log('Server started on port %d', port)
})
}
Then you can do this:
test.js
var server = require('./index')
test('test server', function (t) {
servertest(server(), '/path/to/test', function (err, data) {
// ...
})
})
Or you could reuse the same server
object but that's probably not so savoury for testing.
API
servertest(server, uri, options, callback)
Full arguments form, taking an http.Server
instance (or similar object that performs a listen()
), the uri
to append to http://localhost
and the random port number assigned on the listen()
, the options
object which is mostly passed on to hyperquest. The callback
function will receive either an Error
as the first argument or a special response
object that contains data about the response, see below
servertest(server, uri, callback)
The options
argument is optional, default options will be used for hyperquest, including assuming this is a GET request.
var stream = servertest(server, uri, { method: 'POST' }, callback)
A common POST request form whereby you have a WritableStream you can write data to (either via a pipe()
or simply write()
and end()
).
var stream = servertest(server, uri, { method: 'POST' })
Don't use a callback
function to receive the data. Instead, the stream
is a DuplexStream which has some metadata on the stream
object (including the request
object direct from hyperquest) and you will need to pipe()
it to a WritableStream (or read()
or on('data')
, whatever you prefer).
options
-
'encoding'
: the only option servertest currently cares about. If you provide'utf8'
thecallback
will receive aString
rather than aBuffer
. If you provide'json'
the data received from the server will be passed throughJSON.parse()
and any exceptions will be returned as theError
argument to thecallback
.
hyperquest uses the following options:
-
'method'
: request method, defaults to'GET'
-
'headers'
: anObject
({}
) defining headers to set on the request -
'auth'
: if HTTP authentication is required, must be of the form'user:pass'
Plus a bunch more for HTTPS.
response
The callback
receives a special response
object containing data from the server. It will have the following properties:
-
'headers'
: anObject
containing a mapping of the header keys and values received from the server -
'statusCode'
: the status code of the response from the server -
'body'
: the response body. By default it will be aBuffer
. If you use'utf8'
as the'encoding'
you'll get aString
and if you use'json'
as the'encoding'
you'll get whateverJSON.parse()
gives you for the response string.
error
when servertest
has an encoding error like this case, you can access a response
with the default encoding UTF-8
or utf8
from error.response
, this should give you, the users, much clue as to what your program went wrong.
License
servertest is Copyright (c) 2014 Rod Vagg @rvagg and licenced under the MIT licence. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE.md file for more details.