Express+Typescript: Properly mocking jwt.verify in unit test

zhifei
2 min readMay 14, 2023

Problem

I was trying to find a way to test a Promise function that’s nested inside jwt.verify which isn’t a non-async function that receives a callback function:

const foo = () => {
jwt.verify(
'access-token',
'api-secret',
{},
async (err, decode) => {
await promiseFunction(); // <-- need to test this
},
);
}

To be fair, I was able to mock jwt.verify just fine:

jest.mocked(jwt.verify).mockImplementation(
jest.fn((_token, _secretOrPublicKey, _options, callback) => {
return callback(null, { id: 0 });
})
);

foo();

expect(promiseFunction).toHaveBeenCalledWith({ id: 0 });

However, it’s testing the promiseFunction nested inside the callback function that’s the real headache, because when running the test, I kept getting errors where I’m told I have “incomplete async function” and “Did you forget to use await".

Understandably, it’s because foo isn’t asynchronous, and I didn’t “await” until it’s completed before calling the assertion.

Solution

The solution is fairly simple — turn foo into an asynchronous function~!

To do so, I’ll start by turning jwt.verify into a Promise based function:

import jwt from 'jsonwebtoken';

export async function jwtVerify(token: string, secret: string): Promise<any> {
return new Promise((resolve, reject) => {
jwt.verify(token, secret, (err, decoded) => {
if (err) return reject(err);
resolve(decode);
});
});
}

Next, I’ll replace the old callback function for jwt.verify with the new jwtVerify:

const foo = async () => {
try {
const decode = await jwtVerify('access-token', 'api-secret';
await promiseFunction(decode);
} catch (e) {
// log error
}
}

Then, I can just mock jwtVerify’s return values using either mockResolvedValue (success) or mockRejectedValue (failed):

// success
jest.mocked(jwtVerify).mockRejectedValue({} as VerifyErrors);

// failed
jest.mocked(jwtVerify).mockRejectedValue({} as VerifyErrors);

Finally, I can await foo function to have been called (and completed), before calling the assertions:

jest.mocked(jwt.verify).mockImplementation(
jest.fn((_token, _secretOrPublicKey, _options, callback) => {
return callback(null, { id: 0 });
})
);

await foo();

expect(promiseFunction).toHaveBeenCalledWith({ id: 0 });

--

--

zhifei

Software engineer. Jack of all stacks, master of none.