Testing APIs in Next.js
The latest version of Next.js (which uses the App Router) allows developers to define APIs using Route Handlers. APIs are then defined by the location of the route.js
file (which defines the URL) and the exported function (which defines the HTTP method: GET, POST, etc). Documentation exists for creating the routes, but how to test those routes is left to the user.
In previous Next.js iterations, I had used node-mocks-http
. But the App Router updates makes that solution no longer an option. Instead I utilized a mixture of directly creating Request
objects and mocking any downstream dependencies with Jest.
Creating a Request
In the test, to create the request I wrapped Request
with NextRequest
. For example, to send a request to test /api/widgets
:
const req = new NextRequest(new Request('http://domain/api/widgets'), { method: 'GET', }); const res = await GET(req);
Note that the HTTP protocol and the domain do not matter here, but need to be supplied to fullfil the requirement of the request/response processing. So simply putting http://domain
will suffice.
Running this test will send an empty GET request to /api/widgets
and set the response in res
. You could then verify the response data with something like:
expect(res.status).toEqual(200);
Mocking the Downstream Dependencies
If your API makes database calls, you may want to mock those calls or provide stubs, or a combination. In this example we'll use Jest to mock the Next.js Server Action function which loads the widgets, named getWidgets
.
Imagine this is the API code:
export async function GET(request: NextRequest) { const response = await getWidgets(); return Response.json(response); }
In your test, you could mock getWidgets
like so:
const mockGetWidgets = jest.fn(); jest.mock('<path_to_actions>/actions/widgets', () => ({ getWidgets: (...args: unknown[]) => mockGetWidgets(...args), }));
Then in the test, let's have the widgets return a list of strings: ["hello", "you"]. Our full test would then be:
mockGetWidgets.mockReturnValue(['hello', 'you']); const req = new NextRequest(new Request('http://domain/api/widgets'), { method: 'GET', }); const res = await GET(req); expect(mockGetWidgets).toHaveBeenCalled(); expect(res.status).toEqual(200); expect(await res.json()).toEqual(['hello', 'you']);