Node.js 用Jest测试NextJSAPI中间件
我在NextJS中有一个API路由和中间件设置,如下所示: /src/middleware/validateData/index.tsNode.js 用Jest测试NextJSAPI中间件,node.js,typescript,express,jestjs,next.js,Node.js,Typescript,Express,Jestjs,Next.js,我在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 (handle
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);
};
};
import { NextApiRequest, NextApiResponse } from 'next';
import validateData from '../../middleware/validateData';
const foo = (req: NextApiRequest, res: NextApiResponse) => {
res.send('It works!');
};
export default validateData(foo);
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();
});
});
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();
});
});
/src/api/foo.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);
};
};
import { NextApiRequest, NextApiResponse } from 'next';
import validateData from '../../middleware/validateData';
const foo = (req: NextApiRequest, res: NextApiResponse) => {
res.send('It works!');
};
export default validateData(foo);
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();
});
});
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();
});
});
模式引用是一个验证req.body
数据的@hapi/joi
模式,我没有包括它,因为我认为它与问题无关
我想知道如何单独对中间件进行单元测试?这大概是我所知道的:
/src/middleware/validateData/index.test.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);
};
};
import { NextApiRequest, NextApiResponse } from 'next';
import validateData from '../../middleware/validateData';
const foo = (req: NextApiRequest, res: NextApiResponse) => {
res.send('It works!');
};
export default validateData(foo);
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();
});
});
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();
});
});
但是使用这种技术,我首先得到类型错误,即mockReq
和mockRes
缺少属性(因此我想我需要正确地模拟这些属性,但不确定如何模拟),其次测试失败,因为尽管传递了无效的主体数据,但没有调用res.send
有人知道如何正确地模拟和测试这一点吗
我觉得我的方法是完全错误的,因为我想检查整个响应(状态代码、收到的特定消息等等)。是启动模拟服务器并实际模拟api调用或其他内容的唯一方法吗?在这种情况下,您可以使用
节点模拟http
包
/src/middleware/validateData/index.test.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);
};
};
import { NextApiRequest, NextApiResponse } from 'next';
import validateData from '../../middleware/validateData';
const foo = (req: NextApiRequest, res: NextApiResponse) => {
res.send('It works!');
};
export default validateData(foo);
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();
});
});
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();
});
});
从“节点模拟http”导入httpmock;
从“下一步”导入{NextApiRequest,nextapireresponse};
从“/validateData”导入validateData;
描述('validateData',()=>{
const mockHandler=jest.fn();
const mockReq=httpMocks.createRequest();
const mockRes=httpMocks.createResponse();
它('以错误响应',()=>{
validateData(mockHandler)(mockReq、mockRes);
expect(mockRes.send).tohavebeincall();
});
});
您可以在这样的情况下使用节点模拟http
包
/src/middleware/validateData/index.test.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);
};
};
import { NextApiRequest, NextApiResponse } from 'next';
import validateData from '../../middleware/validateData';
const foo = (req: NextApiRequest, res: NextApiResponse) => {
res.send('It works!');
};
export default validateData(foo);
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();
});
});
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();
});
});
从“节点模拟http”导入httpmock;
从“下一步”导入{NextApiRequest,nextapireresponse};
从“/validateData”导入validateData;
描述('validateData',()=>{
const mockHandler=jest.fn();
const mockReq=httpMocks.createRequest();
const mockRes=httpMocks.createResponse();
它('以错误响应',()=>{
validateData(mockHandler)(mockReq、mockRes);
expect(mockRes.send).tohavebeincall();
});
});
是一个软件包(免责声明:我创建了!),它简化了编写下一个API路由的单元测试。它使用UndertheHood生成真正的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中相同的方式运行,因为它们传递的是实际实例,而不是类型脚本类型或模拟
可以找到更多的例子。是一个软件包(免责声明:我创建了!),它简化了编写下一个API路由的单元测试。它使用UndertheHood生成真正的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中相同的方式运行,因为它们传递的是实际实例,而不是类型脚本类型或模拟
可以找到更多的例子