Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Express and Passport OAuth2 with Mocha and Chai

I have an app that is using Express and Passport. I am using the Google OAuth2 Strategy with Passport. I have a few routes that require a login through this strategy.

I'm doing integration tests with Mocha and Chai currently, but I'm unsure how to bypass or work with the OAuth2 authentication that is required for some of my routes.

For instance, here is one of my tests:

it("should list a single item on /items/<id> GET", function(done) {                                                                             
  chai.request(server)
    .get('/items/' + id) 
    .end(function(err, res) {
      res.should.have.status(200);
      res.should.be.json;
      res.body.should.be.a('object');
      res.body.should.have.property('description');
      done();
    }); 
}); 

My route for /items/:id

router.get('/items/:id', auth.isLoggedIn, function(req, res) {
  var item = getItem();
  res.json(item);
});

/items/:id requires a login. Is there a way to bypass the login for testing, or mock a user to that my integration testing will work?

like image 1000
intargc Avatar asked Jul 13 '16 05:07

intargc


2 Answers

I was able to test github OAuth/passport with mocha chai chai-http nock and nock-github-oauth

nock-github-oauth stubs out the token urls

Also manually nocked the github user and email api calls with samples from the GitHub API docs

This is my auth_controller_spec.js

//During the test the env variable is set to test
process.env.NODE_ENV = 'test';

var chai = require('chai');
var chaiHttp = require('chai-http');
var should = chai.should();
var expect = chai.expect

var User = require.main.require('models/User');

// https://gist.github.com/branneman/8048520#7-the-wrapper
var app = require.main.require('app');

chai.use(chaiHttp);


function nockGitHubUserAPI(nock) {
  /**
   * Intercept `https://api.github.com:443/user` API Call.
   */
   nock('https://api.github.com:443')
    .filteringPath(/\/user.+/, '/user')
    .get('/user')
    .reply(200,
      {
        "login": "octocat",
        "id": 1,
        "avatar_url": "https://github.com/images/error/octocat_happy.gif",
        "gravatar_id": "",
        "url": "https://api.github.com/users/octocat",
        "html_url": "https://github.com/octocat",
        "followers_url": "https://api.github.com/users/octocat/followers",
        "following_url": "https://api.github.com/users/octocat/following{/other_user}",
        "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
        "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
        "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
        "organizations_url": "https://api.github.com/users/octocat/orgs",
        "repos_url": "https://api.github.com/users/octocat/repos",
        "events_url": "https://api.github.com/users/octocat/events{/privacy}",
        "received_events_url": "https://api.github.com/users/octocat/received_events",
        "type": "User",
        "site_admin": false,
        "name": "monalisa octocat",
        "company": "GitHub",
        "blog": "https://github.com/blog",
        "location": "San Francisco",
        "email": "[email protected]",
        "hireable": false,
        "bio": "There once was...",
        "public_repos": 2,
        "public_gists": 1,
        "followers": 20,
        "following": 0,
        "created_at": "2008-01-14T04:33:35Z",
        "updated_at": "2008-01-14T04:33:35Z"
      }
    );

/**
 * Intercept `https://api.github.com:443/user/emails` API Call.
 */
  nock('https://api.github.com:443')
    .filteringPath(/\/user\/emails.+/, '/user/emails')
    .get('/user/emails')
    .reply(200,
      [
        {
          "email": "[email protected]",
          "verified": true,
          "primary": true
        }
      ]
    );
}


describe('Auth Controller', (done) => {

  var user, nock, github, mockToken, githubHost;

  before((done) => {
    nock = require('nock');
    nock.enableNetConnect('127.0.0.1');
    github = require('nock-github-oauth');

    nockGitHubUserAPI(nock)

    github.nock(done);
  })

  beforeEach((done) => { //Before each test we reset the database
    User.query().del().then(() => {
      var params = {name: 'bonzo', authtype: 'github', authid: '12345678'}
      // Create a user so the db isn't empty
      // May help us uncover odd bugs
      new User(params).save()
        .then((bonzo) => {
          user = bonzo;
          done();
        })
    })
  });

  after(function(done) {
      nock.cleanAll();
      done();
  });

  describe('github link', () => {
      it('it should redirect to github.com login / approve page', (done) => {
        chai.request(app)
            .get('/auth/github')
            .redirects(0)
            .end((err, res) => {
              expect(res.headers['location']).to.match(/^https:\/\/github.com\/login\/oauth\/authorize/);
              done();
            });
      });
  });

  describe('github callback', () => {
      it(' should poll github api for details, upsert the user and log them in', (done) => {
        var agent = chai.request.agent(app)
          agent.get('/auth/github/callback')
            .query({code : '9835b716e83875665b21' })
            .end((err, res) => {
              // If successful layout displays username on page in (brackets)
              expect(res.text).to.match(/\(octocat\)/);
              done();
            });
      });
  });


  describe('logout', () => {
      it('it should end the session and show login', (done) => {
        chai.request(app)
            .get('/auth/logout')
            .end((err, res) => {
              expect(res.redirects[0]).to.match(/\/$/);
              // If successful layout displays Login links
              expect(res.text).to.match(/Login/);
              done();
            });
      });
  });

});

Full Source code here: https://github.com/stujo/node-express-gamebase

like image 81
stujo Avatar answered Nov 09 '22 03:11

stujo


I figured out how to make this work by mocking isAuthenticated in the request object within my mocha test.

var chai = require('chai');
var chaiHttp = require('chaiHttp');
var server = require('../app');
var should = chai.should();

chai.use(chaiHttp);

// Allows the middleware to think we're already authenticated.
server.request.isAuthenticated = function() {
  return true;
}

describe('Items', function() {
  it('should list all items on / GET', function(done) {
    chai.request(server)
      .get('/')
      .end(function(err, res) {
        res.should.have.status(200);
        res.should.be.json;
        // more tests...
        done();
      });
  });
});
like image 26
intargc Avatar answered Nov 09 '22 03:11

intargc