How to make authenticated requests in mocha test using supertest and agent?

chovy picture chovy · Jul 17, 2014 · Viewed 8.6k times · Source

I'm having trouble getting my authenticated tests to run (server returns 401 Unauthenticated) after logging in.

var should = require('should'),
    _ = require('lodash'),
    app = require('../../../server'),
    mongoose = require('mongoose'),
    User = mongoose.model('User'),
    request = require('supertest');

var user
    , user1;

describe('GET /api/jobs', function () {
    before(function (done) {
        user = new User({
            provider: 'local',
            name: 'Fake User',
            email: '[email protected]',
            password: 'password'
        });

        // Clear users before testing
        User.remove().exec();

        request(app)
            .post('/api/users')
            .send(user)
            // end handles the response
            .end(function(err, res) {
                if (err) {
                    throw err;
                }

                res.should.have.status(200);
                res.body._id.should.exist;

                user1 = request.agent(app); //user1 will be used in all subsequent tests since he's supposed to be authenticated
                user1
                    .post('/api/session')
                    .send({ email: user.email, password: user.password })
                    .end(function(err, res) {
                        if ( err ) throw err;
                        // user1 will manage its own cookies
                        // res.redirects contains an Array of redirects
                        res.should.have.status(200);

                        done();
                    });
            });
    });

    afterEach(function (done) {
        User.remove().exec();
        done();
    });

    it('should create a job by user1', function (done) {
        var job = {
            //jobs stuff
        };

        user1
            .post('/api/jobs')
            .send(job)
            .expect(200) //It fails here, getting 401 Unauthenticated. Session is using passport local strategy
            .expect('Content-Type', /json/)
            .end(function (err, res) {
                if (err) return done(err);
                res.body.should.be.instanceof(Object);

                done();
            });
    });
});

The sesssion is setting a cookie like this:

    if (req.user) {
        res.cookie('user', JSON.stringify(req.user.userInfo));
    }

Answer

chovy picture chovy · Jul 18, 2014

Made a stupid mistake. I was using before() instead of beforeEach() to create and login the user.

beforeEach(function (done) {
// do stuff before each test
});

The afterEach() was deleting Users in the db.

Here's the full solution if anyone is interested:

beforeEach(function (done) {
    // Clear data before testing
    user1 = {
        name: 'Fake User',
        username: 'test',
        email: '[email protected]',
        password: 'password'
    };

    user2 = {
        name: 'Fake User2',
        username: 'test2',
        email: '[email protected]',
        password: 'password2'
    };

    job = {
        email: '[email protected]'
        , title: 'Title'
        , description: 'Job description that is at least 60 characters with much detail'
        , apply: 'Application instructions'
        , company: 'Company'
        , location: 'Location'
    };

    function createUser1(cb){
        agent1
            .post('/api/users')
            .send(user1)
            .expect(200)
            .end(function(err, res){
                if ( err ) throw err;

                loginUser1.call(null, cb);
            });
    }

    function loginUser1(cb){
        agent1
            .post('/api/session')
            .send({
                email: user1.email
                , password: user1.password
            })
            .expect(200)
            .end(function(err, res){
                if ( err ) throw err;

                loggedInUser1 = res.body;

                cb();
            });
    }

    function createUser2(cb){
        agent2
            .post('/api/users')
            .expect(200)
            .send(user2)
            .end(function(err, res){
                if (err) throw err;

                loginUser2.call(null, cb);
            });
    }

    function loginUser2(cb){
        agent2
            .post('/api/session')
            .send({
                email: user2.email
                , password: user2.password
            })
            .end(function(err, res){
                if ( err ) throw err;

                loggedInUser2 = res.body;

                cb();
            });
    }

    async.series([function(cb){
        createUser1(cb);
    }, function(cb){
        createUser2(cb);
    }], done);

    //working, but looks like shiet with callbacks
    //      agent1
    //          .post('/api/users')
    //          .send(user1)
    //          .expect(200)
    //          // end handles the response
    //          .end(function(err, res) {
    //              if (err) throw err;
    //
    //              agent1
    //                  .post('/api/session')
    //                  .send({
    //                      email: user1.email
    //                      , password: user1.password
    //                  })
    //                  .expect(200)
    //                  .end(function(err, res) {
    //                      if ( err ) throw err;
    //
    //                      loggedInUser1 = res.body;
    //
    //                      //login the 2nd user
    //                      agent2
    //                          .post('/api/users')
    //                          .expect(200)
    //                          .send(user2)
    //                          // end handles the response
    //                          .end(function(err, res) {
    //                              if (err) throw err;
    //
    //                              agent2
    //                                  .post('/api/session')
    //                                  .send({
    //                                      email: user2.email
    //                                      , password: user2.password
    //                                  })
    //                                  .end(function(err, res) {
    //                                      if ( err ) throw err;
    //
    //                                      loggedInUser2 = res.body;
    //
    //                                      done();
    //                                  });
    //                          });
    //                  });
    //          });
});

afterEach(function (done) {
    User.remove()
        .execQ()
        .then(function(){
            return Job.remove().execQ()
        })
        .done(function(){
            done();
        });
});

agent1 is the request as promised object.

var requestp = require("supertest-as-promised");
var agent1 = requestp.agent(app)