【问题标题】:Test NextJS API middleware with Jest用 Jest 测试 NextJS API 中间件
【发布时间】:2020-09-25 13:45:29
【问题描述】:

我在 NextJS 中有一个带有中间件设置的 API 路由,如下所示:

/src/middleware/validateData/index.ts

import { NextApiRequest, NextApiResponse } from 'next';
import schema from './schema';

type Handler = (req: NextApiRequest, res: NextApiResponse) => void;

export default (handler: Handler) => {
  return (req: NextApiRequest, res: NextApiResponse) => {
    const { error } = schema.validate(req.body, { abortEarly: false });
    if (error) res.status(400).send(error);
    else handler(req, res);
  };
};

/src/api/foo.ts

import { NextApiRequest, NextApiResponse } from 'next';

import validateData from '../../middleware/validateData';

const foo = (req: NextApiRequest, res: NextApiResponse) => {
  res.send('It works!');
};

export default validateData(foo);

架构引用是一个 @hapi/joi 架构,用于验证 req.body 数据,我没有包含它,因为我认为它与问题无关。

我想知道如何自己对中间件进行单元测试?这是我所得到的:

/src/middleware/validateData/index.test.ts

import validateData from './validateData';

describe('validateData', () => {
  const mockHandler = jest.fn();

  const mockReq = {
    body: '',
  };

  const mockRes = {
    send: jest.fn(),
  };

  it('responds with error', () => {
    validateData(mockHandler)(mockReq, mockRes);
    expect(mockRes.send).toHaveBeenCalled();
  });
});

但是使用这种技术,我首先会得到 mockReqmockRes 缺少属性的类型错误(所以我想我需要正确地模拟这些但不确定如何),其次测试失败,因为 res.send 不是尽管传递了无效的正文数据,但仍被调用。

有人知道如何正确模拟和测试吗?

我觉得我的方法完全错误,因为我想检查整个响应(状态代码、收到的特定消息等)。是启动模拟服务器并实际模拟 api 调用或其他什么的唯一方法吗?

【问题讨论】:

  • 您找到解决方案了吗?
  • 您可能需要先将类型转换为unknown,然后再转换为NextApiRequestNextApiResponse 类型。这对我有用。例如as unknown as NextApiRequest

标签: node.js typescript express jestjs next.js


【解决方案1】:

next-test-api-route-handler 是一个包(免责声明:我创建!),它简化了为 Next API 路由编写单元测试。它在后台使用test-listen 来生成真正的HTTP 响应。例如:

import validateData from './validateData';
import { testApiHandler } from 'next-test-api-route-handler';

describe('validateData', () => {
  it('responds with error', async () => {
    await testApiHandler({
      handler: validateData((_, res) => res.send('It works!')),
      test: async ({ fetch }) => {
        // Returns a real ServerResponse instance
        const res = await fetch();
        // Hence, res.status == 200 if send(...) was called above
        expect(res.status).toBe(200);
        // We can even inspect the data that was returned
        expect(await res.text()).toBe('It works!');
      }
    });
  });
});

这样,您还可以在测试中直接检查获取的响应对象。更好的是,您的 API 路由处理程序将与 Next.js 中的功能完全相同,因为它们传递的是实际的 NextApiRequest and NextApiResponse 实例而不是 TypeScript 类型或模拟。

更多例子可以在on GitHub找到。

【讨论】:

    【解决方案2】:

    您可以像这样在您的情况下使用node-mocks-http

    /src/middleware/validateData/index.test.ts

    import httpMocks from 'node-mocks-http';
    import { NextApiRequest, NextApiResponse } from 'next';
    import validateData from './validateData';
    
    describe('validateData', () => {
        const mockHandler = jest.fn();
        const mockReq = httpMocks.createRequest<NextApiRequest>();
        const mockRes = httpMocks.createResponse<NextApiResponse>();
    
        it('responds with error', () => {
            validateData(mockHandler)(mockReq, mockRes);
            expect(mockRes.send).toHaveBeenCalled();
        });
    });
    

    【讨论】:

    猜你喜欢
    • 2021-07-04
    • 2021-10-31
    • 2021-11-02
    • 1970-01-01
    • 2020-05-17
    • 2020-12-10
    • 1970-01-01
    • 2017-01-24
    • 2021-02-03
    相关资源
    最近更新 更多