Authenticated Supertest Tests
When you're trying to test your authenticated URLs via supertest, there are just a couple things you'll need to do that aren't spelled out in the docs.
Supertest
Supertest is a library written by the prolific TJ Holowaychuk. It is a companion to superagent. Superagent provides a clean API for issuing HTTP commands. Supertest ties into superagent for allowing easy assertions on top of those HTTP requests.
Authenticated Requests
Lots of webapps have portions of their sites that require authenticated to access, so it makes sense that there's a great need to test requests against these portions. Yet in supertest, there's not a totally-straightforward way to login for the sake of a test and do subsequent requests under that login. At least there's no explicit API for it in the current release. But there have been many requests for it. Who knows if it will come. Given that we know the mechanism for session continuity between requests, cookies, we can make it happen ourselves.
Login for Supertest
Use Superagent
Supertest has no cookiejar for holding cookies like the sessionid. But, superagent does. So, we're going to need to import it explicitly. A login helper could look something like this:
var superagent = require('superagent');
var agent = superagent.agent();
var theAccount = {
"username": "nacho",
"password": "iamtheluchadore"
};
exports.login = function (request, done) {
request
.post('/login')
.send(theAccount)
.end(function (err, res) {
if (err) {
throw err;
}
agent.saveCookies(res);
done(agent);
});
};
A few points:
theAccount
information could come from anywhere. You could use the same pattern from this login process to setup a newly-registered user as well.- The
request
parameter tologin()
is the supertest request. - After we post to '/login' and a response returns in the
end()
function, we are saving the cookies from that response (a login response should return with a 'Set-cookies' header). This superagent agent (with the login cookie) is what we send back to the caller of the login helper viadone()
.
Attach the Cookies to Supertest
Now that we've made login request and saved the cookies, it's time to make our authenticated request(s). Easy cheesy. A simple test to see if the login worked might look like this:
var request = require('supertest')(app);
var login = require('./login');
describe('MyApp', function () {
var agent;
before(function (done) {
login.login(request, function (loginAgent) {
agent = loginAgent;
done();
});
});
it('should allow access to admin when logged in', function (done) {
var req = request.get('/admin');
agent.attachCookies(req);
req.expect(200, done);
});
});
More jabber about the code:
app
is my Express app. This is your webserver.- We're importing the login helper, and we've called it one time before all the tests in our
MyApp
spec viabefore()
. This call tobefore()
is asynchronous, just like our test in this case, because we have to do a full login to setup our test. When theloginAgent
is returned, we save it for use in our actual tests. - The test gets the best of both worlds. When doing
request.get()
, we're using the supertest request. So, we can then do coolexpect()
s on it. Right before the request goes out the door, we grab the superagentagent
and attach its cookies to our new request.
In the future, perhaps there will be a more expressive way to do this that's worked into the supertest API. For now, this strategy is the best I've found. It's based on the method I originally found in visionmedia/supertest#46.
Is there a better way that you've found to do this kind of authenticated test?