super-request
is a supertest
inspired HTTP assertion tester.
super-request
is very similar to supertest
except that it leverages the request
module and supports sessions and chaining of HTTP requests.
npm install super-request
var request = require('super-request'),
express = require('express');
var app = express();
app.use(express.cookieParser());
app.use(express.cookieSession({secret: "super-request123"}));
app.get('/login', function (req, res) {
req.session.loggedIn = true;
res.send("logged in");
});
app.get('/', function (req, res) {
if (req.session.loggedIn) {
req.session.loggedIn = true;
res.send("loggedIn");
} else {
res.send("notLoggedIn");
}
});
request(app)
.get('/login')
.expect(200, "logged in")
.end()
//after we logged in perform this request in the same session!
.get("/")
.expect(200, "loggedIn")
.end(function(err){
if(err){
throw err;
}
});
Here is an example using with mocha
.
describe('GET /users', function(){
it('respond with json', function(done){
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
})
})
super-request
also returns a promise so you can use it with promise based test frameworks here is an an example using it
and returning a promise.
it.describe('GET /users', function(it){
it.should('respond with json', function(){
return request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.end();
});
});
.expect(status[, fn])
Assert response status code.
.expect(status, body[, fn])
Assert response status code and body.
.expect(body[, fn])
Assert response body text with a string, regular expression, or parsed body object.
.expect(field, value[, fn])
Assert header field value with a string or regular expression.
.end(fn)
Perform the request and invoke fn(err, res).
super-request
is a wrapper on top of request
so any options you can specify with request you can also set using the chainable api, by invoking a function with the same name as the option you wish to set.
Methods (see request
)
All option methods listed below allow functions to be passed as the argument in place of the default value. The function must return a valid object, int, string etc. that the option would normally accept. See the "Simple token-auth example" below.
uri
||url
- fully qualified uri or a parsed url object from url.parse()qs
- object containing querystring values to be appended to the urimethod
- http method, defaults to GETheaders
- http headers, defaults to {}body
- entity body for POST and PUT requests. Must be buffer or string.form
- when passed an object this will setbody
but to a querystring representation of value and addsContent-type: application/x-www-form-urlencoded; charset=utf-8
header. When passed no option a FormData instance is returned that will be piped to request.json
- setsbody
but to JSON representation of value and addsContent-type: application/json
header. Additionally, parses the response body as json.multipart
- (experimental) array of objects which contains their own headers andbody
attribute. Sendsmultipart/related
request. See example below.followRedirect
- follow HTTP 3xx responses as redirects. defaults to true.followAllRedirects
- follow non-GET HTTP 3xx responses as redirects. defaults to false.maxRedirects
- the maximum number of redirects to follow, defaults to 10.encoding
- Encoding to be used onsetEncoding
of response data. If set tonull
, the body is returned as a Buffer.pool
- A hash object containing the agents for these requests. If omitted this request will use the global pool which is set to node's default maxSockets.pool.maxSockets
- Integer containing the maximum amount of sockets in the pool.timeout
- Integer containing the number of milliseconds to wait for a request to respond before aborting the requestproxy
- An HTTP proxy to be used. Support proxy Auth with Basic Auth the same way it's supported with theurl
parameter by embedding the auth info in the uri.oauth
- Options for OAuth HMAC-SHA1 signing, see documentation above.strictSSL
- Set totrue
to require that SSL certificates be valid. Note: to use your own certificate authority, you need to specify an agent that was created with that ca as an option.jar
- Set tofalse
if you don't want cookies to be remembered for future use or define your custom cookie jar (see examples section)aws
- object containing aws signing information, should have the propertieskey
andsecret
as well asbucket
unless you're specifying your bucket as part of the path, or you are making a request that doesn't use a bucket (i.e. GET Services)httpSignature
- Options for the HTTP Signature Scheme using Joyent's library. The keyId and key properties must be specified. See the docs for other options.
request(app)
.post("/login")
.form({username : "username", password : "password"})
.expect(200)
.expect({loggedIn : true})
.end(function(err){
if(err){
throw err;
}
});
To upload data to a server
request(app)
.post("/upload/csv")
.headers({'content-type': 'multipart/form-data'})
.multipart([
{
'Content-Disposition': 'form-data; name="file"; filename="my.csv"',
'Content-Type': 'text/csv',
body: fs.readFileSync(path.resolve(__dirname, "./assets/my.csv"))
}
])
.expect(200)
.expect("content-type", "text/plain")
.end(function(err){
if(err){
throw err;
}
});
super-request
supports chaining of requests, this is particularly useful if you need to login to your server and then perform a request.
request(app)
.post("/login")
.form({username : "username", password : "password"})
.expect(200)
.expect({loggedIn : true})
.end() //this request is done
//now start a new one in the same session
.get("/some/protected/route")
.expect(200, {hello : "world"})
.end(function(err){
if(err){
throw err;
}
});
Note You must call end on the current request before you can start a new one.
Using everything learned above, let's try a more complex example. This example illustrates using functions as the argument for your options. This is useful for request chains that need to lazily evaluate a value returned from your http api. Consider the extremely simplified example of a token authentication flow:
/**
* Webserver setup
**/
var request = require('super-request'),
express = require('express'),
app = express();
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.cookieSession({secret: 'super-request123'}));
// a public available route, must post email/password to the body
app.post('/login', function (req, res) {
var body = req.body;
if (!!body.email && !!body.password) {
req.session.token = Math.random();
res.send(''+req.session.token);
} else {
res.send(400)
}
});
// a "private" route that requires a valid token in the query string.
app.get('/', function (req, res) {
var query = req.query || {};
if (query.token && parseFloat(query.token) === req.session.token) {
res.send('tokenValid');
} else {
res.send(401);
}
});
// create a request super-request
var token;
request(app)
.post('/login')
.form({
email: '[email protected]',
password: 'pass1234'
})
.expect(200)
.end(function (err, res, body) {
// store the token, we will use it later in the request chain.
token = body;
})
// after we have our token, adding the token to the query string gives access to protected routes
// note: querystrings are an unsafe option for token auth in production, but works for a simple example.
.get('/')
.qs(function () {
return {token: token};
})
.expect(200, 'tokenValid')
.end()
// a request without a token or a bogus token protected routes cannot be reached.
.get('/')
.expect(401)
.end(function(err){
if(err){
throw err;
}
});