【问题标题】:Mocking jsonwebtoken module with Jest用 Jest 模拟 jsonwebtoken 模块
【发布时间】:2021-02-04 20:43:49
【问题描述】:

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

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

但是打字稿给我发了这个错误: 类型'{(令牌:字符串,secretOrPublicKey:秘密,选项?:验证选项|未定义)上不存在属性'mockReturnValue':字符串|目的; (token: string, secretOrPublicKey: string | Buffer | { key: string | Buffer; passphrase: string; } | GetPublicKeyOrSecret, callback?: VerifyCallback | undefined): void; (令牌:字符串,secretOrPublicKey:字符串| ... ...'。

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

大家知道问题出在哪里,或者如何在玩笑时模拟这个 jsonwebtoken 模块吗?

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)
            })
})

验证.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' })
    }

最好的问候

【问题讨论】:

    标签: node.js testing jestjs mocking jwt


    【解决方案1】:

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

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

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

    【讨论】:

    • 未测试,但应该足够接近
    • 您好,感谢您的快速回答。我测试了您的解决方案,实际上它解决了我的问题,但我们不想在 mockReturnValue 的参数中获取对象。错误消息说他等待无效响应,但我认为我可以调整返回类型? const { verify } = jwt as jest.Mocked&lt;typeof import('jsonwebtoken')&gt; verify.mockReturnValue({ userId: member._id }) 类型参数 '{ userId: Schema.Types.ObjectId; }' 不可分配给“void”类型的参数
    • verify方法有多种实现,其中一种返回void。 ts 无法找出您要使用的 impl。尝试使用const verify = jwt.verify as jest.MockedFunction&lt;( token: string, secretOrPublicKey: jwt.Secret, options?: jwt.VerifyOptions, ) =&gt; object | string&gt;;
    【解决方案2】:

    我花了一段时间,但我得到了这个工作,有几节课。

    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
       }));
      
    3. 然后我可以通过以下三种方式之一模拟验证:

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

    b) 使用 mockReturnValue,但我需要指定要替换的重载(感谢 @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) 使用模拟实现

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

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

    【讨论】:

    • 如果需要,您可以使用 mockRestore() 函数从 jwt.verify 函数中删除模拟。请注意,这将在您调用该函数后删除规范文件中所有内容的模拟实现。见jest docs
    【解决方案3】:

    使用verify同时返回解码后的token时:

    jest.mock('jsonwebtoken', () => ({
      verify: jest.fn((token, secretOrPublicKey, options, callback) => {
        return callback(null, {sub: 'user_id'});
      })
    }));
    

    【讨论】:

      猜你喜欢
      • 2019-08-17
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      • 2021-12-04
      • 2019-08-15
      • 2019-06-09
      • 2019-08-28
      相关资源
      最近更新 更多