trysis trysis - 3 months ago 9
Node.js Question

Access to "req" Object in Supertest After a Response

Is there any way to directly access the

req
object in
supertest
, while/after the request is being tested? I want to test my
passport
strategies, so I want to check
req.user
,
req.session
, and perhaps others. I know I can test page redirects or flash, as those are what my strategies do, but it seems useful to see if there is a user on the
req
object, as well. If I do this, I can also check how many users there are at any one time.

I will sign users up with the "local-signup" strategy, which is defined thusly:

'use strict';

// get passport & mongoose
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var UserModel = require('mongoose').model('User');

module.exports = function() {

// signup function
passport.use('local-signup', new LocalStrategy({
passReqToCallback: true // pass the entire request to the callback
},

function(req, username, password, done) {

process.nextTick(function() {

// find a user with the same username
UserModel.findOne({username: username}, function(err, user) {

// if there is an error, log it then return it
if(err) {
console.log("Error finding a user in the database: " + err);
return done(err);
}

// if a user was already found
if(user) {
return done(null, false, "User already exists");
}

// if we get this far, create a new user from the request body
var newUser = new UserModel(req.body);

// save it and sign it in
newUser.save(function(err) {
if(err) {
console.log("Error during signup: " + err);
return done(err);
}
return done(null, newUser);
});

});

});

}

));

};


One way I use this strategy is like this:

My "local" strategy is defined like this:

'use strict';

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var UserModel = require('mongoose').model('User');

module.exports = function() {

// create our local passport strategy & use it
passport.use(new LocalStrategy({

// use the default names for the username & password fields
usernameField: 'username',
passwordField: 'password'
},

// main strategy function
function(username, password, done) {

// find user with given username
UserModel.findOne({
username: username
},

// with this username, do this
function(err, user) {

// if there's an error, log it then pass it along
if(err) {
console.log("Error during login: " + err);
return done(err);
}

// if the username and/or password is incorrect, return an error
// along with a message
if(!user || !user.authenticate(password)) {
return done(null, false, {
message: 'Invalid username and/or password'
});
}

// if everything is correct, return the user document from the database
return done(null, user);

});
}

));
};


I use both strategies like this, for example:

app.route(pageName).post(function(req, res, next) {
passport.authenticate(strategyName, function(err, user, info) {
if(err || !user) {
res.status(401).send(info);
}
else {
req.login(user, function(err) {
if(err) {
res.status(400).send(err);
}
else {
res.send(null);
}
});
}
})(req, res, next);
});


I tried

request = require('supertest');
this.authServer = require('../my-server');

request(this.authServer)
.put('/signup')
.set('Content-Type', 'application/json')
.set('Host', 'konneka.org')
.send(this.fullUser)
.end(function(req, res, done) {
console.log(res);
});


The
res
object I logged, inside the
end()
function, which was way too long to show here, has a
req
object defined on it, but it seems to only have the objects & functions that were defined before the request was opened. In other words, it does not have
req.user
,
req.session
, or other objects I want, because they are defined after the request completes and a new request is started. I noticed it has status codes, as well, which are only defined after the request completes, so I must be missing something.

Is there any way to get access to the
req
object after the request you are testing is ended?
Or am I going about this completely the wrong way?

Answer

You cannot do what you want using supertest.

Not sure if this helps but I'll add a little context to clarify the answer:

supertest is a wrapper on top of superagent (client side) with some basic hooks into express to start up the HTTP listener. Under the hood, it really is not any different from starting up your express app, waiting for it to listen on a port, making an HTTP request to that port, and parsing the result. In fact, that is exactly what it does.

So essentially supertest only has access to what ever your client would have access to (a browser or some API client). In other words, if it isnt in the HTTP response body, you wont have access to it. req.user and req.sesssion are server side state variables that are (most likely) not in the response (unless you are doing something strange).

If you want to test in exactly the way you describe, you will have to use some alternative strategy of testing, not supertest.