使用正确类型使用 Jest 和 Typescript 模拟 Express 请求
Posted
技术标签:
【中文标题】使用正确类型使用 Jest 和 Typescript 模拟 Express 请求【英文标题】:Mocking Express Request with Jest and Typescript using correct types 【发布时间】:2020-01-17 17:32:13 【问题描述】:在 Jest 中获取正确的 Express Request 类型时遇到了一些问题。我有一个使用此代码传递的简单用户注册:
import userRegister from '../../controllers/user';
import Request, Response, NextFunction from 'express';
describe('User Registration', () =>
test('User has an invalid first name', async () =>
const mockRequest: any =
body:
firstName: 'J',
lastName: 'Doe',
email: 'jdoe@abc123.com',
password: 'Abcd1234',
passwordConfirm: 'Abcd1234',
company: 'ABC Inc.',
,
;
const mockResponse: any =
json: jest.fn(),
status: jest.fn(),
;
const mockNext: NextFunction = jest.fn();
await userRegister(mockRequest, mockResponse, mockNext);
expect(mockNext).toHaveBeenCalledTimes(1);
expect(mockNext).toHaveBeenCalledWith(
new Error('First name must be between 2 and 50 characters')
);
);
);
但是,如果我改变:
const mockRequest: any =
body:
firstName: 'J',
lastName: 'Doe',
email: 'jdoe@abc123.com',
password: 'Abcd1234',
passwordConfirm: 'Abcd1234',
company: 'ABC Inc.',
,
;
到:
const mockRequest: Partial<Request> =
body:
firstName: 'J',
lastName: 'Doe',
email: 'jdoe@abc123.com',
password: 'Abcd1234',
passwordConfirm: 'Abcd1234',
company: 'ABC Inc.',
,
;
根据 TypeScript 文档 (https://www.typescriptlang.org/docs/handbook/utility-types.html#partialt),这应该使 Request 对象上的所有字段都是可选的。
但是,我收到此错误:
Argument of type 'Partial<Request>' is not assignable to parameter of type 'Request'.
Property '[Symbol.asyncIterator]' is missing in type 'Partial<Request>' but required in type 'Request'.ts(2345)
stream.d.ts(101, 13): '[Symbol.asyncIterator]' is declared here.
我希望有更多 TypeScript 经验的人可以发表评论并让我知道我做错了什么。
【问题讨论】:
您对Partial<Request>
所做的事情是正确的,但我敢打赌,问题在于userRegister
不接受Partial<Request>
- 它需要Request
对吗?您可以将 mockRequest 声明为 Request
吗? const mockRequest: Partial<Request> ...
如果没有,你可以给我们一个断言:await userRegister(mockRequest as Request, mockResponse, mockNext);
现在看起来像这样:export const userRegister = async ( req: express.Request, res: express.Response, next: express.NextFunction ) =>
。模拟在测试中。我现在通过使用:const mockRequest: any = body: firstName: 'J', lastName: 'Doe', email: 'jdoe@abc123.com', password: 'Abcd1234', passwordConfirm: 'Abcd1234', company: 'ABC Inc.', , ;
解决了这个问题。但我被告知尽量不要使用 any
,因为它违背了 TypeScript 的目的。
啊啊啊。我知道了。是的,userRegister
确实需要 req: express.Request
和 res: express.Response
。有趣,但对于测试,有没有办法解决这个问题?我想我在any
工作时感到困惑。
你能把userRegister函数贴在这里,让我们看看这个函数的类型声明吗?
【参考方案1】:
似乎@kschaer 说userRegister
是问题所在。如果您希望该功能采用Partial<Request>
,您可以将userRegister
更改为:
const userRegister = async (req: Partial<Request>, res: Response, next: NextFunction) => /* snippet */
但由于这仅用于测试,您也可以将 mockRequest
转换为 Request
类型,如下所示:
const mockRequest = <Request>
body:
/* snippet */
;
希望对您有所帮助。
【讨论】:
当我这样做时,我现在得到这个 TS 错误:Type ' body: firstName: string; lastName: string; email: string; password: string; passwordConfirm: string; company: string; ; ' is not assignable to type '<Request>() => any'. Object literal may only specify known properties, and 'body' does not exist in type '<Request>() => any'.
嗯,那么不确定。对不起。【参考方案2】:
您的模拟数据类型不必完全适合实际数据。 好吧,它不是根据定义。这只是一个模拟,对吧?
您需要的是type assertion。这是一种告诉 TypeScript “好的兄弟,我知道我在这里做什么。”。
这不是生产代码,而是测试。您甚至可能在手表模式下运行它。我们可以在这里毫无问题地拒绝某些类型安全。 TypeScript 不知道这是一个模拟,但我们知道。
const mockRequest =
body:
firstName: 'J',
lastName: 'Doe',
email: 'jdoe@abc123.com',
password: 'Abcd1234',
passwordConfirm: 'Abcd1234',
company: 'ABC Inc.',
,
as Request;
如果在测试期间发生崩溃,因为mockRequest
与 Request 不够相似,我们会知道并修复模拟,添加一些新属性等。
如果 as Request
不起作用,你可以告诉 TypeScript“我真的知道我在这里做什么”,首先声明 any
或 unknown
,然后声明你的类型需要。它看起来像
const x: number = "not a number :wink:" as any as number;
当我们想测试我们的代码在输入错误的情况下不能很好地工作时,它很有用。
对于你的特殊情况——模拟快递请求——有jest-express可以帮助你,当然如果你可以节省 node_modules 的大小。
【讨论】:
我知道有事!感谢您的提醒。 现在当我调用userRegister
函数时,我得到了这个 TS 错误 Argument of type 'Request' is not assignable to parameter of type 'import("/Users/nrb/Development/partsync-server/node_modules/@types/express/index").Request'. Type 'Request' is missing the following properties from type 'Request': get, header, accepts, acceptsCharsets, and 68 more.ts(2345)
嘿尼克B。你有两个请求。一个是全局的,在@types/node 中输入,另一个来自 Express。这有点烦人。 typescriptlang.org/play/…
如果它仍然中断,您可以简单地将as Request
替换为as any as Request
或简单地as any
。太感谢了。很好的答案。以上是关于使用正确类型使用 Jest 和 Typescript 模拟 Express 请求的主要内容,如果未能解决你的问题,请参考以下文章
通过 npm 脚本从 Powershell 使用 --collectCoverageFrom 运行 Jest 测试时,转义引号和斜杠的正确方法是啥?