用 Jest 测试 NextJS API 中间件
Posted
技术标签:
【中文标题】用 Jest 测试 NextJS API 中间件【英文标题】:Test NextJS API middleware with Jest 【发布时间】: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();
);
);
但是使用这种技术,我首先会得到 mockReq
和 mockRes
缺少属性的类型错误(所以我想我需要正确地模拟这些但不确定如何),其次测试失败,因为 res.send
不是尽管传递了无效的正文数据,但仍被调用。
有人知道如何正确模拟和测试吗?
我觉得我的方法完全错误,因为我想检查整个响应(状态代码、收到的特定消息等)。是启动模拟服务器并实际模拟 api 调用或其他什么的唯一方法吗?
【问题讨论】:
您找到解决方案了吗? 您可能需要先将类型转换为unknown
,然后再转换为NextApiRequest
或NextApiResponse
类型。这对我有用。例如as unknown as NextApiRequest
【参考方案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();
);
);
【讨论】:
这仍然对您有用吗?看来我对最新 Next 的打字稿参数有疑问。刚刚在这里创建github.com/howardabrams/node-mocks-http/issues/245以上是关于用 Jest 测试 NextJS API 中间件的主要内容,如果未能解决你的问题,请参考以下文章
如何用 jest 测试此 api 中间件是不是处理 fetch 引发的错误?
在 TypeScript 中使用 NextJS 设置 Jest + React 测试库 -- 设置 upp jest.config.js 时出错
如何使用 jest 在 javascript 中测试 try catch 代码并在 express 中包含带有中间件的 next() 调用?