HttpRequestHandler
An HTTP request handler to declare responses for intercepted requests. When multiple handlers of the same interceptor
match the same method and path, the last handler created with
interceptor.<method>(path) will be
used.
HttpRequestHandler operationsIf you are using a remote interceptor, make sure to await the handler before making requests. This is because many
remote handler operations are asynchronous and require communication with the
interceptor server.
If you don't await the handler, your declarations may not be committed to the server before the requests are made,
leading to non-deterministic behavior. A single await is enough, even if you are making multiple declarations, as
HttpRequestHandler automatically batches all changes.
// Instead of awaiting each operation separately:
const handler = interceptor.patch('/users/:userId');
await handler.with((request) => /^\d+$/.test(request.pathParams.userId));
await handler.with({ body: { username: 'new-username' } });
await handler.respond({ status: 204 });
await handler.times(1);
// You can await the handler once:
const handler = await interceptor
.patch('/users/:userId')
.with((request) => /^\d+$/.test(request.pathParams.userId))
.with({ body: { username: 'new-username' } })
.respond({ status: 204 })
.times(1);
When using a local interceptor, you can safely skip awaiting the handler, as all operations are synchronous and immediate.
handler.method
The method that matches this handler.
Type: HttpMethod (readonly)
handler.path
The path that matches this handler. The base URL of the interceptor is not included, but it is used when matching requests.
Type: string (readonly)
handler.with()
Declares a restriction to intercepted request matches. headers, searchParams, and body are supported to limit
which requests will match the handler and receive the mock response. If multiple restrictions are declared, either in a
single object or with multiple calls to handler.with(), all of them must be met, essentially creating an AND
condition.
By default, restrictions use exact: false, meaning that any request containing the declared restrictions will
match the handler, regardless of having more properties or values. If you want to match only requests with the exact
values declared, use exact: true.
- Local interceptor
- Remote interceptor
handler.with(restriction);
handler.with((request) => matchesRequest);
await handler.with(restriction);
await handler.with((request) => matchesRequest);
Arguments:
-
restriction:
HttpRequestHandlerRestriction<Schema, Method, Path>The restriction to match intercepted requests. It can be static, defined as an object with the following properties:
-
headers:
HttpRequestHandlerHeadersStaticRestriction<Schema, Method, Path> | undefinedA set of headers that the intercepted request must contain to match the handler. If exact is
true, the request must contain exactly these headers and no others. -
searchParams:
HttpRequestHandlerSearchParamsStaticRestriction<Schema, Method, Path> | undefinedA set of search params that the intercepted request must contain to match the handler. If exact is
true, the request must contain exactly these search params and no others. -
body:
HttpRequestHandlerBodyStaticRestriction<Schema, Method, Path> | undefinedThe body that the intercepted request must contain to match the handler. If exact is
true, the request must contain exactly this body and no other. -
exact:
boolean | undefined(default:false)If
true, the request must contain exactly the headers, search params, and body declared in this restriction. Otherwise, the request must contain at least them.
Restrictions can also be computed, declared as a function to dynamically decide how to check the request:
Arguments:
-
request:
HttpInterceptorRequest<Path, MethodSchema>The intercepted request to check against the restriction.
Returns:
Promise<boolean> | booleanA boolean indicating whether the intercepted request matches the restriction.
-
Returns: HttpRequestHandler<Method, Path, StatusCode>
The same handler, now considering the specified restriction.
If the interceptor is local, the restriction is immediately applied to the handler. If the interceptor is remote, the restriction is asynchronously sent to the interceptor server. Because of the asynchronous nature of remote interceptors, make sure to await the handler before making requests.
Related:
handler.delay()
Declares a delay to wait before responding to requests. This is useful for simulating network latency, server processing time, or testing loading states in your application, for example.
- Local interceptor
- Remote interceptor
handler.delay(milliseconds);
handler.delay(minMilliseconds, maxMilliseconds);
handler.delay((request) => milliseconds);
await handler.delay(milliseconds);
await handler.delay(minMilliseconds, maxMilliseconds);
await handler.delay((request) => milliseconds);
Arguments:
-
milliseconds:
number | HttpRequestHandlerResponseDelayFactory<Path, MethodSchema>The delay to apply before responding, in milliseconds. It can be either:
- An exact number for static delays, or;
- A function that returns the delay, which can be useful to generate dynamic delays based on the request.
-
maxMilliseconds (optional):
numberIf two arguments are provided, the first is considered the minimum delay and the second the maximum delay, both in milliseconds. Each response will have a random delay within this range, calculated using
Math.random().
Returns: HttpRequestHandler<Method, Path, StatusCode>
The same handler, now including the configured delay.
Related:
handler.respond()
Declares a response to return for matched intercepted requests.
When the handler matches a request, it will respond with the given declaration. The response type is statically validated against the schema of the interceptor.
- Local interceptor
- Remote interceptor
handler.respond(declaration);
handler.respond((request) => declaration);
await handler.respond(declaration);
await handler.respond((request) => declaration);
Arguments:
-
declaration:
HttpRequestHandlerResponseDeclaration<MethodSchema, StatusCode> | HttpRequestHandlerResponseDeclarationFactory<MethodSchema, StatusCode>The response declaration or a factory to create it. It can be a static object:
-
status:
HttpStatusCodeThe status code for the response.
-
headers:
HttpHeadersInit<HeadersSchema> | undefinedThe headers to include in the response.
-
body:
HttpBodyThe body to include in the response.
A declaration can also be a function to dynamically decide how to respond to the request:
Arguments:
-
request:
HttpInterceptorRequest<Path, MethodSchema>The intercepted request to respond to.
Returns:
Promise<HttpRequestHandlerResponseDeclaration<MethodSchema, StatusCode>> | HttpRequestHandlerResponseDeclaration<MethodSchema, StatusCode> -
Returns: HttpRequestHandler<Method, Path, StatusCode>
The same handler, now including type information about the response declaration based on the status code.
If the interceptor is local, the response is immediately applied to the handler. If the interceptor is remote, the response is asynchronously sent to the interceptor server. Because of the asynchronous nature of remote interceptors, make sure to await the handler before making requests.
handler.times()
Declares a number of intercepted requests that the handler will be able to match and return its response.
If only one argument is provided, the handler will match exactly that number of requests. In case of two arguments, the handler will consider an inclusive range, matching at least the minimum (first argument) and at most the maximum (second argument) number of requests.
Once the handler receives more requests than the maximum number declared, it will stop matching requests and returning its response. In this case, Zimic will try other handlers until one eligible is found; otherwise the request will be either bypassed or rejected.
- Local interceptor
- Remote interceptor
handler.times(numberOfRequests);
handler.times(minNumberOfRequests, maxNumberOfRequests);
await handler.times(numberOfRequests);
await handler.times(minNumberOfRequests, maxNumberOfRequests);
Arguments:
-
numberOfRequests:
numberIf only one argument is provided, this is the exact number of requests to match. If two arguments are provided, this is considered a minimum.
-
maxNumberOfRequests:
number | undefinedIf two arguments are provided, this is the maximum number of requests to match.
Returns: HttpRequestHandler<Method, Path, StatusCode>
The same handler, now considering the specified number of requests.
To make sure that all expected requests were made, use
interceptor.checkTimes() or
handler.checkTimes().
interceptor.checkTimes() is generally
preferred, as it checks all handlers created by the interceptor with a single call.
Related:
handler.checkTimes()
Checks if the handler has matched the expected number of requests declared with handler.times().
If the handler has matched fewer or more requests than expected, this method will throw a TimesCheckError error
pointing to the handler.times() API reference that was not satisfied.
This is useful at the end of a test to ensure that all expected requests were made. If you are calling
interceptor.checkTimes() after each test,
you can skip this call, as it will be called automatically for all handlers created by the interceptor.
When requestSaving.enabled is true in
your interceptor, the TimesCheckError errors will also list each unmatched request with diff of the expected and
received data. This is useful for debugging requests that did not match a handler with
handler.with restrictions.
- Local interceptor
- Remote interceptor
handler.checkTimes();
Returns: void
await handler.checkTimes();
Returns: Promise<void>
handler.clear()
Clears any response declared with handler.respond(), restrictions declared with
handler.with(), and intercepted requests, making the handler stop matching requests. The next handler,
created before this one, that matches the same method and path will be used if present. If not, the requests of the
method and path will not be intercepted.
To make the handler match requests again, register a new response with handler.respond().
- Local interceptor
- Remote interceptor
handler.clear();
await handler.clear();
Returns: HttpRequestHandler<Method, Path, StatusCode>
The same handler, now cleared of any response, restrictions, and intercepted requests.
handler.requests
The intercepted requests that matched this handler, along with the responses returned to each of them. This is useful to allow additional validation in tests, if you are not using declarative assertions or you need more advanced checks.
Type: InterceptedHttpInterceptorRequest<Path, MethodSchema, StatusCode>[]
handler.requests requires request saving to be enabledThis method can only be used if
requestSaving.enabled is true in the
interceptor.