Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking jsonwebtoken module with Jest

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

like image 645
Seyrinian Avatar asked Apr 20 '26 14:04

Seyrinian


1 Answers

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.

like image 90
iamonkey Avatar answered Apr 23 '26 05:04

iamonkey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!