1
votes

I try to mock with jest the verify function of the npm module jsonwebtoken. The function return a decoded token but i want to pass a custom return of this function my unit test.

I made express request that check the validity of access tokent before proceed to request. But I want to mock the moment of the token check to return directly the user value. And pass easily this step. I put you the concern part of code.

But typescript send me this error: Property 'mockReturnValue' does not exist on type '{ (token: string, secretOrPublicKey: Secret, options?: VerifyOptions | undefined): string | object; (token: string, secretOrPublicKey: string | Buffer | { key: string | Buffer; passphrase: string; } | GetPublicKeyOrSecret, callback?: VerifyCallback | undefined): void; (token: string, secretOrPublicKey: string | ... ...'.

So the mock isn't working and I don't understant. I follow the mock axios step on Jest.io but it's didn't seem apply to jsonwebtoken.

Is everyone know what is the problem or how to mock this jsonwebtoken module on jest ?

users.test.ts

import jwt from 'jsonwebtoken'
    jest.mock('jwt')
    jwt.verify.mockReturnValue({
                    userId: String(member._id),
                    email: String(member.email),
                    permissionLevel: member.permissionLevel,
                    username: String(member.username),
                })

describe('### /GET users', () => {
            it('it should return 200 (Users List)', async (done) => {
                const res = await request(app).set('Authorization', 'Bearer').get('/users')
                expect(res.status).toBe(200)
            })
})

Validation.ts

public isAccessTokenValid = (req: Request, res: Response, next: NextFunction): void => {
        if (req.cryptedAccessToken) {
            try {
                req.accessToken = jwt.verify(req.cryptedAccessToken, ACCESS_TOKEN_SECRET)
                next()
            } catch (err) {
                res.status(498).send({ error: err.message })
            }
        } else res.status(401).send({ error: 'cryptedAccessToken field not present in request' })
    }

Best regards

2

2 Answers

0
votes

That would be because TypeScript "doesn't knows" that you've mocked the module, so you can try to typecast the correct type

import jwt from 'jsonwebtoken'
const { verify } = jwt as jest.Mocked<typeof import('jsonwebtoken')>

verify.mockReturnValue({
  //...
})

or

(jwt as jest.Mocked<typeof import('jsonwebtoken')>).verify.mockReturnValue({
  //...
})
1
votes

It took me a while, but I got this working, with a few lessons.

  1. jest.mock('jsonwebtoken') needs to be used and it must be placed at the top of the spec file, just after import jwt from 'jsonwebtoken'

  2. Doing this mocks all of the functions of jwt. In my case I just wanted to mock verify. This code resolves that (replacing (1) above).

     import jwt from 'jsonwebtoken;
     jest.mock('jsonwebtoken', () => ({
     ...jest.requireActual('jsonwebtoken'), // import and retain the original functionalities
     verify: jest.fn().mockReturnValue({ foo: 'bar' }), // overwrite verify
     }));
    
  3. I could then mock verify in one of three ways:

a) Leave it as the default mock (returning foo bar)

b) Using mockReturnValue, but I need to specify which overload I'm replacing (thx @Gabriel)

  const verify = jwt.verify as jest.MockedFunction<
    (
      token: string,
      secretOrPublicKey: jwt.Secret,
      options?: jwt.VerifyOptions,
    ) => Record<string, unknown> | string
  >;
  verify.mockReturnValue({ verified: 'true' });

c) Using mock implementation

 const verify = jest.spyOn(jwt, 'verify');
 verify.mockImplementation(() => () => ({ verified: 'true' }));

The annoying thing with all of these is that verify is now mocked for all describe/it in the spec file.