【问题标题】:Testing Express / Passport middleware using Jasmine — passport.authenticate never completes使用 Jasmine 测试 Express / Passport 中间件——passport.authenticate 永远不会完成
【发布时间】:2015-11-10 21:09:26
【问题描述】:

我正在尝试对一个简单的 Express 中间件进行单元测试,这是一个级联认证器,它首先使用 passport-jwt-strategy 检查 JWT 令牌,然后如果失败,则使用 passport-openid-strategy。每个策略都已经过很好的测试,所以我要测试的是它们的集成。

我正在测试的模块如下所示:

"use strict";

let passport = require('passport');
let Strategies = require('./strategies');
let setupDone = false;

// set up passport
let setup = function(app) {
  passport.serializeUser(function(user, done) {
    done(null, user);
  });

  passport.deserializeUser(function(obj, done) {
    done(null, obj);
  });

  passport.use('jwt',    Strategies.jwt);
  passport.use('openid', Strategies.openId);
  app.use(passport.initialize());
  app.use(passport.session());
  setupDone = true;
};

let authenticate = function(req, res, next) {
  if (!setupDone) throw new Error('You must have run setup(app) before you can use the middleware');
  console.log(' cascadingAuthentication');
  // first try the token option
  passport.authenticate('jwt', function(jwterr, user, info) {
    console.log(' jwt auth', jwterr, user, info);
    if (jwterr || !user) {
      passport.authenticate('openid, function(oautherr, user, info) {
        if (oautherr || !user) {
          return next(oautherr);
        } else {
          next();
        }
      });
    } else {
      req.user = user;
      next();
    }
  });
};

module.exports = {
  setup: setup,
  authenticate: authenticate
}

我的Jasmine 测试看起来像这样

"use strict";

let CascadingAuthentication = require('../../lib/middleware/cascadingAuthentication');
let TokenUtils = require('../support/tokenUtils');
let email = 'testing@test.tes;

describe('cascadingAuthentication', function() {

  describe('when there is a token in the header', function() {
    let req;
    let res = {};
    let app = {
      use: function(used) { console.log('app.use called with', typeof used); }
    };

    beforeEach(function(done) {
      let token = TokenUtils.makeJWT(email);
      req = {
        app: app,
        header: {
          Authorization: `Bearer ${token}`
        }
      }
      CascadingAuthentication.setup(app);
      CascadingAuthentication.authenticate(req, res, function() {
        done();
      });
    });

    it('populates req.user', function() {
      expect(req.user).toEqual(jasmine.any(Object));
    });
  });

});

我遇到的问题是,当我运行测试时,我看到了第一个 console.log(' cascadingAuthentication'),但我从来没有看到第二个 console.log('jwt auth', err, user, info)。代码只是在passport.authenticate 内死掉,没有调用回调,没有引发错误,或者根本没有提供任何反馈。

我正在通过gulp 使用Jasmine 运行我的测试。

我的问题是:按顺序,

  1. 您能看出我所做的任何明显而我可能错过的事情吗?
  2. 在我的reqresapp 中还有什么我应该模拟的东西可以使这个测试工作吗?
  3. 有什么办法可以交互调试吗?在运行时单步执行被测代码,而不是仅仅添加 console.log 语句(这对我来说似乎有点 1980 年代)。

【问题讨论】:

    标签: node.js express jasmine passport.js gulp-jasmine


    【解决方案1】:

    挖掘passport 的源代码,我发现我的代码存在两个问题。

    第一个是passport.authenticate 返回一个中间件函数,它实际上并没有执行那个函数。所以解决方法就是调用返回的函数。

    所以我的身份验证方法现在看起来像:

    let authenticate = function(req, res, next) {
      if (!setupDone) throw new Error('You must have run setup(app) before you can use the middleware');
      // first try the token option
      passport.authenticate('jwt', function(jwterr, user, info) {
        if (jwterr || !user) {
          passport.authenticate('openid', function(autherr, user, info) {
            if (autherr || !user) {
              return next(autherr);
            } else {
              next();
            }
          })(req, res, next);
        } else {
          req.user = user;
          next();
        }
      })(req, res, next);
    };
    

    (上面的例子被剪裁以用于问题)

    另一个问题是在我的测试中,我在模拟的req 对象中使用了header 而不是headers,而且authorization 应该有一个小写的a

    通过这两个修复,测试现在通过了。

    【讨论】:

      【解决方案2】:

      我为此摆弄了很长一段时间,最终选择了以下设置(测试passport.authenticate('local', () => {}))。

      auth-router.js

      const express = require('express');
      const passport = require('passport');
      
      const login = (req, res, next) => {
        passport.authenticate('local', (err, user, info) => {
          if (err) {
            next(err);
            return;
          }
      
          if (!user) {
            const error = new Error(info.message);
            error.status = 404;
            next(error);
            return;
          }
      
          // Add the found user record to the request to 
          // allow other middlewares to access it.
          req.user = user;
          next();
        })(req, res, next);
      };
      
      const router = express.Router();
      router.post('/auth/login', login);
      
      module.exports = {
        login,
        router
      };

      auth-router.spec.js

      const passport = require('passport');
      
      describe('login', () => {
        it('should login and add the user to the request object', (done) => {
          spyOn(passport, 'authenticate').and.callFake((strategy, callback) => {
            const err = null;
            const user = {};
            const info = {};
            callback(err, user, info);
            return (req, res, next) => {};
          });
      
          const auth = require('./auth'); // my middleware function
          const req = { body: {} };
          const res = {};
          const next = () => {
            expect(req.user).toBeDefined();
            done();
          };
      
          auth.login(req, res, next);
        });
      });

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多