如何为JWT策略编写单元测试用例

问题描述 投票:0回答:1

我是不是第一次接触password.js,并试图涵盖我的JWT策略的单元测试用例。谁能建议该怎么做?

// Setup JWT strategy for all requests
passport.use(
  new JWTStrategy(
    {
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: JWT_PRIVATE_KEY,
    },
    async (jwtPayload: any, done: any) => {
      const isUser = jwtPayload.type === EntityType.User;
      const model = isUser ? userModel : vendorModel;
      try {
        const document = await model.findOne({ _id: jwtPayload.id });
        if (document) {
          return done(null, jwtPayload);
        } else {
          return done(null, false);
        }
      } catch (err) {
        return done(err, false);
      }
    },
  ),
);
unit-testing jestjs passport.js passport-local passport-jwt
1个回答
0
投票

单元测试解决方案:

index.ts

import passport from 'passport';
import { Strategy as JWTStrategy, ExtractJwt } from 'passport-jwt';
import { userModel, vendorModel, EntityType } from './models';

const JWT_PRIVATE_KEY = 'secret 123';

passport.use(
  new JWTStrategy(
    {
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: JWT_PRIVATE_KEY,
    },
    async (jwtPayload: any, done: any) => {
      console.log('123123');
      const isUser = jwtPayload.type === EntityType.User;
      const model = isUser ? userModel : vendorModel;
      try {
        const document = await model.findOne({ _id: jwtPayload.id });
        if (document) {
          return done(null, jwtPayload);
        } else {
          return done(null, false);
        }
      } catch (err) {
        return done(err, false);
      }
    },
  ),
);

models.ts

export enum EntityType {
  User = 'User',
}
export const userModel = {
  async findOne(opts) {
    return 'real user document';
  },
};
export const vendorModel = {
  async findOne(opts) {
    return 'real vendor document';
  },
};

index.test.ts

import { Strategy as JWTStrategy, ExtractJwt, VerifyCallback, StrategyOptions } from 'passport-jwt';
import passport from 'passport';
import { userModel, vendorModel } from './models';

jest.mock('passport-jwt', () => {
  const mJWTStrategy = jest.fn();
  const mExtractJwt = {
    fromAuthHeaderAsBearerToken: jest.fn(),
  };
  return { Strategy: mJWTStrategy, ExtractJwt: mExtractJwt };
});
jest.mock('passport', () => {
  return { use: jest.fn() };
});

describe('62125872', () => {
  let verifyRef;
  beforeEach(() => {
    const mJwtFromRequestFunction = jest.fn();
    (ExtractJwt.fromAuthHeaderAsBearerToken as jest.MockedFunction<
      typeof ExtractJwt.fromAuthHeaderAsBearerToken
    >).mockReturnValueOnce(mJwtFromRequestFunction);

    (JWTStrategy as jest.MockedClass<any>).mockImplementation((opt: StrategyOptions, verify: VerifyCallback) => {
      verifyRef = verify;
    });
  });

  it('should verify using user model and call done with jwtpayload if user document exists', async () => {
    const payload = { type: 'User', id: 1 };
    const mDone = jest.fn();

    jest.spyOn(userModel, 'findOne').mockResolvedValueOnce('mocked user document');
    await import('./');
    await verifyRef(payload, mDone);
    expect(passport.use).toBeCalledWith(expect.any(Object));
    expect(JWTStrategy).toBeCalledWith(
      { jwtFromRequest: expect.any(Function), secretOrKey: 'secret 123' },
      expect.any(Function),
    );
    expect(ExtractJwt.fromAuthHeaderAsBearerToken).toBeCalledTimes(1);
    expect(userModel.findOne).toBeCalledWith({ _id: 1 });
    expect(mDone).toBeCalledWith(null, { type: 'User', id: 1 });
  });

  it("should verify using user model and call done with false if user document doesn't exist", async () => {
    const payload = { type: 'User', id: 1 };
    const mDone = jest.fn();

    jest.spyOn(userModel, 'findOne').mockResolvedValueOnce('');
    await import('./');
    await verifyRef(payload, mDone);
    expect(passport.use).toBeCalledWith(expect.any(Object));
    expect(JWTStrategy).toBeCalledWith(
      { jwtFromRequest: expect.any(Function), secretOrKey: 'secret 123' },
      expect.any(Function),
    );
    expect(ExtractJwt.fromAuthHeaderAsBearerToken).toBeCalledTimes(1);
    expect(userModel.findOne).toBeCalledWith({ _id: 1 });
    expect(mDone).toBeCalledWith(null, false);
  });

  // you can do the rest parts
});

单元测试结果:

 PASS  stackoverflow/62125872/index.test.ts
  62125872
    ✓ should verify using user model and call done with jwtpayload if user document exists (11ms)
    ✓ should verify using user model and call done with false if user document doesn't exist (2ms)

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |      85 |    83.33 |      60 |   84.21 |                   
 index.ts  |   92.86 |       75 |     100 |   92.31 | 24                
 models.ts |   66.67 |      100 |   33.33 |   66.67 | 6,11              
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        3.716s, estimated 10s
© www.soinside.com 2019 - 2024. All rights reserved.