【问题标题】:Mocking Express Request with Jest and Typescript using correct types使用正确类型使用 Jest 和 Typescript 模拟 Express 请求
【发布时间】: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&lt;Request&gt; 所做的事情是正确的,但我敢打赌,问题在于userRegister 不接受Partial&lt;Request&gt; - 它需要Request 对吗?您可以将 mockRequest 声明为 Request 吗? const mockRequest: Partial&lt;Request&gt; ... 如果没有,你可以给我们一个断言:await userRegister(mockRequest as Request, mockResponse, mockNext);
  • 现在看起来像这样:export const userRegister = async ( req: express.Request, res: express.Response, next: express.NextFunction ) =&gt; {。模拟在测试中。我现在通过使用:const mockRequest: any = { body: { firstName: 'J', lastName: 'Doe', email: 'jdoe@abc123.com', password: 'Abcd1234', passwordConfirm: 'Abcd1234', company: 'ABC Inc.', }, }; 解决了这个问题。但我被告知尽量不要使用 any,因为它违背了 TypeScript 的目的。
  • 啊啊啊。我知道了。是的,userRegister 确实需要 req: express.Requestres: express.Response。有趣,但对于测试,有没有办法解决这个问题?我想我在any 工作时感到困惑。
  • 你能把userRegister函数贴在这里,让我们看看这个函数的类型声明吗?

标签: typescript express jestjs


【解决方案1】:

似乎@kschaer 说userRegister 是问题所在。如果您希望该功能采用Partial&lt;Request&gt;,您可以将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 '&lt;Request&gt;() =&gt; any'. Object literal may only specify known properties, and 'body' does not exist in type '&lt;Request&gt;() =&gt; 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“我真的知道我在这里做什么”,首先声明 anyunknown,然后声明你的类型需要。它看起来像

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。太感谢了。很好的答案。
猜你喜欢
  • 2020-12-18
  • 2018-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-24
  • 2020-02-11
  • 2017-02-26
相关资源
最近更新 更多