【问题标题】:Testing Express and Passport OAuth2 with Mocha and Chai使用 Mocha 和 Chai 测试 Express 和 Passport OAuth2
【发布时间】:2016-11-15 13:39:05
【问题描述】:

我有一个使用 Express 和 Passport 的应用。我正在使用带有 Passport 的 Google OAuth2 策略。我有一些需要通过此策略登录的路线。

我目前正在使用 Mocha 和 Chai 进行集成测试,但我不确定如何绕过或使用我的某些路由所需的 OAuth2 身份验证。

例如,这是我的一项测试:

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

/items/:id我的路线

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

/items/:id 需要登录。有没有办法绕过登录进行测试,或者模拟用户让我的集成测试可以工作?

【问题讨论】:

    标签: node.js express mocha.js passport.js chai


    【解决方案1】:

    我能够使用 mocha chai chai-http nock 和 nock-github-oauth 测试 github OAuth/passport

    nock-github-oauth 存根令牌网址

    还使用来自 GitHub API 文档的示例手动锁定 github 用户和电子邮件 api 调用

    这是我的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": "octocat@github.com",
            "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": "octocat@github.com",
              "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();
                });
          });
      });
    
    });
    

    完整源代码在这里:https://github.com/stujo/node-express-gamebase

    【讨论】:

      【解决方案2】:

      我想出了如何通过在我的 mocha 测试中的请求对象中模拟 isAuthenticated 来完成这项工作。

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

      【讨论】:

        【解决方案3】:

        如果你愿意,你可以制作自己的方法来绕过它,但最好是也测试登录,然后你可以测试需要用户登录的功能。

        我以前从未使用过 Chai,但您可能可以这样做:

        var user = null;
        
        it("should log the user in", function(done) {                                                                             
          chai.request(server)
            .post('/login', userCredentials) 
            .end(function(err, res) {
              res.should.have.status(200);
              user = res.body;
              done();
            }); 
        });
        

        【讨论】:

        • 这个问题是它使用了谷歌 OAuth2 身份验证方法,这需要对谷歌的身份验证进行大量重定向和回调。这不是典型的本地身份验证方法。
        • @intargc - 我得到了这个在 github 上工作 - 请看示例代码,OAuth 和 API 请求的 nocking 应该与 google 类似,让我知道你遇到了什么问题!
        猜你喜欢
        • 1970-01-01
        • 2020-10-11
        • 1970-01-01
        • 2013-04-11
        • 2015-11-06
        • 2018-02-27
        • 1970-01-01
        • 1970-01-01
        • 2017-02-18
        相关资源
        最近更新 更多