doug-martin / super-request

super-request is a supertest inspired HTTP assertion tester.
http://doug-martin.github.com/super-request/
MIT License
32 stars 12 forks source link

build status

Super Request

super-request is a supertest inspired HTTP assertion tester.

About

super-request is very similar to supertest except that it leverages the request module and supports sessions and chaining of HTTP requests.

Installation

npm install super-request

Example


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;
        }
    });

Using with testing frameworks

Mocha

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();
  });
});

API

.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.

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;
        }
    });

Chaining requests

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.

Simple token-auth example

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: 'john@isp.com',
        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;
        }
    });