Тестирование промежуточного программного обеспечения 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
,
Мои вопросы: по порядку,
- Можете ли вы увидеть что-нибудь очевидное, что я сделал, что я мог просто пропустить?
- Есть ли что-то еще, что я должен издеваться в моем
req
,res
, или жеapp
что может заставить этот тест работать? - Есть ли способ отладить это в интерактивном режиме; пошаговое выполнение тестируемого кода, а не просто добавление
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
,
С этими двумя исправлениями тест теперь проходит.