簡體   English   中英

使用正確類型使用 Jest 和 Typescript 模擬 Express 請求

[英]Mocking Express Request with Jest and Typescript using correct types

我在 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 經驗的人可以發表評論並讓我知道我做錯了什么。

您的模擬數據類型不必完全適合實際數據。 好吧,它不是根據定義。 這只是一個模擬,對吧?

您需要的是類型斷言 這是一種告訴 TypeScript “好的兄弟,我知道我在這里做什么”的方式。 .

這不是生產代碼,而是測試。 您甚至可能在手表模式下運行它。 我們可以在這里毫無問題地拒絕某些類型安全。 TypeScript 不知道它是一個模擬,但我們知道。

const mockRequest = {
    body: {
    firstName: 'J',
    lastName: 'Doe',
    email: 'jdoe@abc123.com',
    password: 'Abcd1234',
    passwordConfirm: 'Abcd1234',
    company: 'ABC Inc.',
    },
} as Request;

如果在測試過程中發生崩潰,因為mockRequest與 Request 不夠相似,我們會知道並修復 mock,添加一些新屬性等。

如果as Request不起作用,你可以告訴 TypeScript “我真的知道我在這里做什么” ,首先斷言anyunknown然后再斷言你需要的類型。 它看起來像

const x: number = "not a number :wink:" as any as number;

當我們想測試我們的代碼在輸入錯誤的情況下不能很好地工作時,它很有用。

對於您的特定情況 - 模擬快遞請求 - 如果您當然可以節省 node_modules 的大小,則可以使用jest-express來幫助您。

為了將來搜索這個主題,我建議查看這個庫: https ://www.npmjs.com/package/node-mocks-http

該庫具有為 Express 框架的請求和響應創建模擬對象的方法,這對我有很大幫助,並且是我找到的簡單方法。

簡單的單元測試示例:

import { Request, Response } from 'express';
import {
  createRequest, createResponse, MockRequest, MockResponse,
} from 'node-mocks-http';
import { AppController } from './app-controller';
import { APP_NAME, APP_VERSION } from '../../constants';

describe('AppController - UnitTestCase', () => {
  let controller: AppController;
  let request: MockRequest<Request>;
  let response: MockResponse<Response>;
  beforeEach(() => {
    controller = new AppController();
    /** Response Mock */
    response = createResponse();
  });

  it('should be defined', () => {
    expect(controller).toBeDefined();
  });

  describe('GET /', () => {
    it('should return 200 and API Name + API Version', (done) => {
      /** Request Mock */
      request = createRequest({
        method: 'GET',
        url: '/',
      });

      AppController.index(request, response);

      const body = { app: `${APP_NAME}:${APP_VERSION}` };
      const result = response._getJSONData();
      expect(result).toMatchObject(body);
      expect(result.app).toEqual(body.app);
      expect(response.getHeaders()).toHaveProperty('content-type');
      console.log('headers', response.getHeaders());
      console.log('response body', result);
      done();
    });
  });
});

似乎userRegister是@kschaer 所說的問題。 如果您希望該函數接受Partial<Request> ,您可以將userRegister更改為:

const userRegister = async (req: Partial<Request>, res: Response, next: NextFunction) => { /* snippet */ }

但由於這只是用於測試,您也可以將mockRequest轉換為Request類型,如下所示:

const mockRequest = <Request>{
  body: {
    /* snippet */
  }
};

希望這會有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM