用 Jest 模拟 jsonwebtoken 模块
Posted
技术标签:
【中文标题】用 Jest 模拟 jsonwebtoken 模块【英文标题】:Mocking jsonwebtoken module with Jest 【发布时间】: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' )
最好的问候
【问题讨论】:
【参考方案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<typeof import('jsonwebtoken')> verify.mockReturnValue( userId: member._id )
类型参数 ' userId: Schema.Types.ObjectId; ' 不可分配给“void”类型的参数
verify方法有多种实现,其中一种返回void。 ts 无法找出您要使用的 impl。尝试使用const verify = jwt.verify as jest.MockedFunction<( token: string, secretOrPublicKey: jwt.Secret, options?: jwt.VerifyOptions, ) => object | string>;
【参考方案2】:
我花了一段时间,但我得到了这个工作,有几节课。
需要使用jest.mock('jsonwebtoken')
,并且必须放在spec文件的顶部,紧跟import jwt from 'jsonwebtoken'
之后
这样做会模拟 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
));
然后我可以通过以下三种方式之一模拟验证:
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');
)
));
【讨论】:
以上是关于用 Jest 模拟 jsonwebtoken 模块的主要内容,如果未能解决你的问题,请参考以下文章