UNPKG

next-test-api-route-handler

Version:

Confidently unit and integration test your Next.js API routes/handlers in an isolated Next.js-like environment

179 lines 7.56 kB
import type { IncomingMessage, ServerResponse } from 'node:http'; import type { NextApiHandler } from 'next'; import type { NextRequest } from 'next/server'; /** * @internal */ export declare const $originalGlobalFetch: unique symbol; /** * @internal */ export declare const $isPatched: unique symbol; /** * @internal */ export type Promisable<Promised> = Promised | Promise<Promised>; /** * @internal */ export type FetchReturnType<NextResponseJsonType> = Promise<Omit<Response, 'json'> & { json: (...args: Parameters<Response['json']>) => Promise<NextResponseJsonType>; cookies: ReturnType<typeof import('cookie').parse>[]; }>; export interface NtarhInit<NextResponseJsonType = unknown> { /** * If `false`, errors thrown from within a handler are kicked up to Next.js's * resolver to deal with, which is what would happen in production. If `true`, * the {@link testApiHandler} function will reject immediately instead. * * You should use `rejectOnHandlerError` whenever you want to manually handle * an error that bubbles up from your handler (which is especially true if * you're using `expect` _within_ your handler) or when you notice a false * negative despite exceptions being thrown. * * @default false */ rejectOnHandlerError?: boolean; /** * `test` is a function that runs your test assertions. This function receives * one destructured parameter: `fetch`, which is equivalent to * `globalThis.fetch` but with the first parameter omitted. */ test: (parameters: { fetch: (customInit?: RequestInit) => FetchReturnType<NextResponseJsonType>; }) => Promisable<void>; } type AppRouteUserlandModule = import('next/dist/server/route-modules/app-route/module').AppRouteUserlandModule; /** * The parameters expected by `testApiHandler` when using `appHandler`. */ export interface NtarhInitAppRouter<NextResponseJsonType = unknown> extends NtarhInit<NextResponseJsonType> { /** * The actual App Router route handler under test. It should be an object * containing one or more async functions named for valid HTTP methods and/or * a valid configuration option. See [the Next.js * documentation](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) * for details. */ appHandler: Partial<Omit<AppRouteUserlandModule, keyof import('next/dist/server/route-modules/app-route/module').AppRouteHandlers> & { [key in keyof import('next/dist/server/route-modules/app-route/module').AppRouteHandlers]?: (req: NextRequest, segmentData?: any) => any }>; pagesHandler?: undefined; /** * `params` is passed directly to the handler and represents processed dynamic * routes. This should not be confused with query string parsing, which is * handled by `Request` automatically. * * `params: { id: 'some-id' }` is shorthand for `paramsPatcher: (params) => { * params.id = 'some-id' }`. This is useful for quickly setting many params at * once. */ params?: Record<string, string | string[]>; /** * A function that receives `params`, an object representing "processed" * dynamic route parameters. Modifications to `params` are passed directly to * the handler. You can also return a custom object from this function which * will replace `params` entirely. * * Parameter patching should not be confused with query string parsing, which * is handled by `Request` automatically. */ paramsPatcher?: (params: Record<string, string | string[]>) => Promisable<void | Record<string, string | string[]>>; /** * A function that receives a `NextRequest` object and returns a `Request` * instance. Use this function to edit the request _before_ it's injected * into the handler. * * If the returned `Request` instance is not also an instance of * `NextRequest`, it will be wrapped with `NextRequest`, e.g. `new * NextRequest(returnedRequest, { ... })`. */ requestPatcher?: (request: import('next/server').NextRequest) => Promisable<void | Request>; /** * A function that receives the `Response` object returned from `appHandler` * and returns a `Response` instance. Use this function to edit the response * _after_ your handler runs but _before_ it's processed by the server. * * Note that `responsePatcher` is called even in the case of exceptions, * including _unhandled exceptions_ (for which Next.js returns an HTTP 500 * response). The only time `responsePatcher` is not called is when an * unhandled exception occurs _and_ `rejectOnHandlerError` is `true`. */ responsePatcher?: (res: Response) => Promisable<void | Response>; /** * `url: 'your-url'` is shorthand for `requestPatcher: (request) => new * NextRequest('your-url', request)` */ url?: string; } /** * The parameters expected by `testApiHandler` when using `pagesHandler`. */ export interface NtarhInitPagesRouter<NextResponseJsonType = unknown> extends NtarhInit<NextResponseJsonType> { /** * The actual Pages Router route handler under test. It should be an async * function that accepts `NextApiRequest` and `NextApiResult` objects (in * that order) as its two parameters. * * Note that type checking for `res.send` and similar methods was retired in * NTARH@4. Only the `response.json` method returned by NTARH's fetch wrapper * will have a typed result. */ pagesHandler: NextApiHandler | { default: NextApiHandler; }; appHandler?: undefined; /** * `params` is passed directly to the handler and represents processed dynamic * routes. This should not be confused with query string parsing, which is * handled automatically. * * `params: { id: 'some-id' }` is shorthand for `paramsPatcher: (params) => { * params.id = 'some-id' }`. This is useful for quickly setting many params at * once. */ params?: Record<string, unknown>; /** * A function that receives `params`, an object representing "processed" * dynamic route parameters. Modifications to `params` are passed directly to * the handler. You can also return a custom object from this function which * will replace `params` entirely. * * Parameter patching should not be confused with query string parsing, which * is handled automatically. */ paramsPatcher?: (params: Record<string, unknown>) => Promisable<void | Record<string, unknown>>; /** * A function that receives an `IncomingMessage` object. Use this function * to edit the request _before_ it's injected into the handler. * * **Note: all replacement `IncomingMessage.header` names must be * lowercase.** */ requestPatcher?: (request: IncomingMessage) => Promisable<void>; /** * A function that receives a `ServerResponse` object. Use this function * to edit the response _before_ it's injected into the handler. */ responsePatcher?: (res: ServerResponse) => Promisable<void>; /** * `url: 'your-url'` is shorthand for `requestPatcher: (req) => { req.url = * 'your-url' }` */ url?: string; } /** * Uses Next's internal `apiResolver` (for Pages Router) or an * `AppRouteRouteModule` instance (for App Router) to execute api route handlers * in a Next-like testing environment. */ export declare function testApiHandler<NextResponseJsonType = any>({ rejectOnHandlerError, requestPatcher, responsePatcher, paramsPatcher, params, url, pagesHandler: pagesHandler_, appHandler, test }: NtarhInitAppRouter<NextResponseJsonType> | NtarhInitPagesRouter<NextResponseJsonType>): Promise<void>; export {};