Тестирование промежуточного программного обеспечения Express / Passport с использованием Jasmine - passport.authenticate никогда не завершается

Я пытаюсь провести модульное тестирование простой части промежуточного программного обеспечения Express, каскадного аутентификатора, который сначала проверяет токен JWT, используя passport-jwt-strategyи затем, если это не удается, используя 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. Есть ли что-то еще, что я должен издеваться в моем req, res, или же app что может заставить этот тест работать?
  3. Есть ли способ отладить это в интерактивном режиме; пошаговое выполнение тестируемого кода, а не просто добавление console.log заявления (что кажется немного 1980-х годов для меня).

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

Копаем 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);
};

(Приведенный выше пример обрезан для использования в вопросе)

Другая проблема была в моем тесте, который я использовал header вместо headers в моем насмешке req объект, а также authorization должен был иметь нижний регистр a,

С этими двумя исправлениями тест теперь проходит.

Другие вопросы по тегам