开发者问题收集

使用 Jest 实现护照的简单模拟功能

2019-03-12
11258

我目前正在对所有路线进行单元测试,包括一些使用自定义护照身份验证功能的路线。我试图模拟护照功能来测试错误处理,但我一直收到错误:

TypeError: _passport.default.authenticate(...) is not a function

这是在 /controllers/users.js 中运行的实际代码:

export const persistentLogin = (req, res, next) => {
  // Authenicate the cookie sent on the req object.
  passport.authenticate('jwt', { session: false }, async (authErr, user) => {
    // If there is an system error, send 500 error
    if (authErr) return res.sendStatus(500);

    // If no user is returned, send response showing failure.
    if (!user) {
      return res.status(200).json({
        success: 'false',
      });
    }
  })(req, res, next);
};

这是 /tests/controllers/users.js 中的测试代码:

import passport from 'passport';
import { persistentLogin } from '../../controllers/users';

beforeEach(() => {
  mockResponse = () => {
    const response = {};
    response.status = jest.fn().mockReturnValue(response);
    response.json = jest.fn().mockReturnValue(response);
    response.sendStatus = jest.fn().mockReturnValue(response);
    response.clearCookie = jest.fn().mockReturnValue(response);
    response.cookie = jest.fn().mockReturnValue(response);
    return response;
  };
});

/**
 * persistentLogin Tests
 */
describe('Persistent Login Controller', () => {
  beforeEach(() => {
    req = {};

    res = mockResponse();

    validateLoginForm.mockClear();
    bcrypt.compare.mockClear();
  });

  // Passport authenication error
  test('Should show passport authenication error', async () => {
    passport.authenticate = jest.fn((authType, options, callback) => callback('This is an error', null));

    await persistentLogin(req, res);

    expect(passport.authenticate).toHaveBeenCalledTimes(1);

    expect(res.sendStatus).toHaveBeenCalledWith(500);
  });
});

如果我不得不猜测,我会说这与事后如何将 (req、res、next) 对象传递到实时函数有关。但由于我们只是在模拟函数,我不确定它是否真的需要访问这些对象。

编辑 #1:

根据 @jakemingolla 的评论,我现在认为可能是因为 Jest 没有运行定义我的自定义 JWT 策略的 app.js 文件。

这是来自 /app.js 文件的代码:

import passport from 'passport';
import passportJWTStrategy from './utils/auth/passport';

app.use(passport.initialize());
passportJWTStrategy(passport);

以及来自 /utils/auth/passport.js 文件的代码:

import { Strategy } from 'passport-jwt';

/**
 * Verifies JWT payload
 *
 * @param passport The instance of passport module.
 */
export default (passport) => {
  const JWTStrategy = Strategy;

  // Setup Options Object
  const opts = {};
  opts.jwtFromRequest = req => req.cookies.jwt;
  opts.secretOrKey = process.env.PASSPORT_SECRET;

  passport.use(
    new JWTStrategy(opts, (jwtPayload, done) => {
      if (Date.now() > jwtPayload.expire_date) {
        return done('jwt expired');
      }

      return done(null, jwtPayload);
    }),
  );
};
2个回答

您只需要一个小更改:

您的模拟 Passport.authenticate 只需要返回 function

435330739
Brian Adams
2019-03-12

在问题中,您模拟了 passport.authenticate ,但在这种情况下,您的策略的 verify 函数未被调用。如果您还想运行此函数或模拟特定策略,请尝试以下操作:

sinon
    .stub(passport._strategies.google, 'authenticate')
    .callsFake(function verified() {
        const self = this;
        this._verify(
            null,
            null,
            {
                _json: { email: faker.internet.email() },
                name: {
                    givenName: faker.name.firstName(),
                    familyName: faker.name.lastName(),
                },
            },
            (err, user, info) => {
                if (err) {
                    return self.error(err);
                }
                if (!user) {
                    return self.fail(info);
                }
                return self.success(user, info);
            }
        );
    });
const response = await supertest(app)
    .get('/google/callback?code=123');
Eugene
2022-02-18