使用 Jest 模拟 jsonwebtoken 模块

Sey*_*ian 9 testing mocking node.js jwt jestjs

我尝试用玩笑来模拟 npm 模块 jsonwebtoken 的验证功能。该函数返回一个已解码的令牌,但我想将此函数的自定义返回传递给我的单元测试。

我明确请求在继续请求之前检查访问令牌的有效性。但我想模拟令牌检查的时刻以直接返回用户值。并且轻松通过这一步。我把代码中关注的部分给你了。

但打字稿向我发送此错误: 类型 '{ 上不存在属性 'mockReturnValue' (令牌:字符串,secretOrPublicKey:秘密,选项?:VerifyOptions | 未定义):字符串 | 目的; (令牌:字符串,secretOrPublicKey:字符串 | 缓冲区 | { 密钥:字符串 | 缓冲区;密码:字符串; } | GetPublicKeyOrSecret,回调?:VerifyCallback | 未定义):void;(令牌:字符串,secretOrPublicKey:字符串| ... ...'。

所以模拟不起作用,我不明白。我遵循 Jest.io 上的模拟 axios 步骤,但它似乎不适用于 jsonwebtoken。

每个人都知道问题是什么或者如何在 jest 上模拟这个 jsonwebtoken 模块吗?

用户.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)
            })
})
Run Code Online (Sandbox Code Playgroud)

验证.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' })
    }
Run Code Online (Sandbox Code Playgroud)

此致

小智 13

我花了一段时间,但通过一些教训,我成功了。

  1. jest.mock('jsonwebtoken')需要使用,并且必须将其放置在spec文件的顶部,紧接在import jwt from 'jsonwebtoken'.

  2. 这样做会模拟 jwt 的所有功能。就我而言,我只是想模拟验证。此代码解决了这个问题(替换上面的 (1))。

     import jwt from 'jsonwebtoken';
     jest.mock('jsonwebtoken', () => ({
     ...jest.requireActual('jsonwebtoken'), // import and retain the original functionalities
     verify: jest.fn().mockReturnValue({ foo: 'bar' }), // overwrite verify
     }));
    
    Run Code Online (Sandbox Code Playgroud)
  3. 然后我可以通过以下三种方式之一进行模拟验证:

a) 将其保留为默认模拟(返回 foo bar)。

b)使用mockReturnValue,但我需要指定要替换的重载(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' });
Run Code Online (Sandbox Code Playgroud)

c) 使用模拟实现:

 const verify = jest.spyOn(jwt, 'verify');
 verify.mockImplementation(() => () => ({ verified: 'true' }));
Run Code Online (Sandbox Code Playgroud)

所有这些令人讨厌的事情是,现在对规范文件中的所有描述/它进行验证。


Ten*_*eff 1

那是因为 TypeScript “不知道”你已经模拟了该模块,所以你可以尝试强制转换正确的类型

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

verify.mockReturnValue({
  //...
})
Run Code Online (Sandbox Code Playgroud)

或者

(jwt as jest.Mocked<typeof import('jsonwebtoken')>).verify.mockReturnValue({
  //...
})
Run Code Online (Sandbox Code Playgroud)