Skip to main content

Client

API Reference

Registering a route handler

API Reference

Registering a route handler allows you to intercept requests and modify the response in various ways via the Route class passed as an argument to the handler.

// Matching URL's with glob patterns
client.route("**/api", (route) => {
return route.fulfill(...);
});

// Matching URL's with regular expressions
client.route(/^.*?\/api$/, (route) => {
return route.fulfill(...);
});

// Matching URL's with a custom function
client.route((url: URL) => {
return url.pathname.startsWith("/api");
}, (route) => {
return route.fulfill(...);
});

URL matching

URL matchers are evaluated against the full request URL, including the protocol, host, path, trailing slash, and query string. There is no automatic normalization, so **/api/path will not match http://localhost/api/path/ or http://localhost/api/path?foo=bar.

warning

Glob patterns must explicitly account for trailing slashes and query strings if you want to ignore them, otherwise requests will fall through to the next handler (or passthrough).

When a string is passed, matching is performed by minimatch. Otherwise the matcher can be a regular expression or a callback that receives a URL instance.

Ignoring trailing slashes and query strings

To match the same route regardless of a trailing slash or query string, use a regular expression or a callback:

// Regular expression
client.route(/\/api\/path\/?(\?.*)?$/, (route) => {
return route.fulfill(...);
});

// Callback - compare only the pathname, ignore search and trailing slash
client.route((url: URL) => {
return url.pathname.replace(/\/$/, "") === "/api/path";
}, (route) => {
return route.fulfill(...);
});

Path parameters

Mocky Balboa does not support named path parameters (e.g. MSW-style /users/:id). Use a glob wildcard, a regular expression, or a callback if you need to match dynamic segments and extract their values from the request URL inside the handler.

// Glob wildcard - matches any single path segment
client.route("**/api/users/*", (route) => {
const userId = new URL(route.request.url).pathname.split("/").pop();
return route.fulfill(...);
});

// Callback - match and extract the parameter
client.route((url: URL) => {
return /^\/api\/users\/[^/]+$/.test(url.pathname);
}, (route) => {
const userId = new URL(route.request.url).pathname.split("/").pop();
return route.fulfill(...);
});

Configure handler priority

Mocky Balboa defaults to calling route handlers in the order they were registered in.

// Matches all user requests
client.route("**/api/user/*", (route) => {
return route.fulfill({
status: 404,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: "Not Found" }),
});
});

// Matches a specific user
client.route("**/api/user/123", (route) => {
return route.fulfill({
status: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: 123, name: 'Test User' }),
});
});

// GET .../api/user/1 -> 404
// GET .../api/user/123 -> ALSO 404

When using the default behavior, make sure to define handlers that should take priority first.

You can change the priority using Client.setHandlerPriority:

// Reverse handler priority
client.setHandlerPriority("last-registered-wins");

// Matches all user requests
client.route("**/api/user/*", (route) => {
return route.fulfill({
status: 404,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: "Not Found" }),
});
});

// Matches a specific user
client.route("**/api/user/123", (route) => {
return route.fulfill({
status: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: 123, name: "Test User" }),
});
});

// GET .../api/user/1 -> still 404
// GET .../api/user/123 -> now gets 200

This can be useful if you want to define situation-specific route handlers in nested test suites or specific tests.

Mock n times

API Reference

The route handler will be removed once its been executed n times.

// Once the route handler is matched 3 times it will be removed from the client
client.route("**/api", (route) => {
return route.fulfill(...);
}, { times: 3 });

Mock client and server side requests (default behaviour)

API Reference

RouteOptions.type defaults to "both" when not explicitly set.

// The route handler will handle requests that originate from the client or server side
client.route("**/api", (route) => {
return route.fulfill(...);
}, { type: "both" });

Only mock server side requests

API Reference

Setting RouteOptions.type to "server-only" will only mock server side requests. This is useful if you differentiate between client and server side requests. For example, authentication strategies can be different between client and server side.

// The route handler will handle requests that originate from the server only
client.route("**/api", (route) => {
return route.fulfill(...);
}, { type: "server-only" });

Only mock client side requests

API Reference

Setting RouteOptions.type to "client-only" will only mock client side requests. This is useful if you differentiate between client and server side requests. For example, authentication strategies can be different between client and server side.

This is the equivalent of Playwright's page.route or Cypress' cy.intercept. This is a convenient interface that allows you to mock requests across the stack without having to call different functions.

// The route handler will handle requests that originate from the client (browser) only
client.route("**/api", (route) => {
return route.fulfill(...);
}, { type: "client-only" });

Unregistering a route handler

API Reference

If you want to disable a route handler, you can use the unroute method:

const routeHandlerId = client.route("**/api", (route) => {
return route.fulfill(...);
});

client.unroute(routeHandlerId);

Unregistering all route handlers

API Reference

Used to unregister all route handlers registered on the client.

client.unrouteAll();

Waiting for a request

When you need to wait for a request to be made, you can use client.waitForRequest.

tip

Use client.waitForRequest to assert on the request being sent on the server.

const requestPromise = client.waitForRequest("**/api");

// Run code that triggers the request, i.e. loading a page

// Await the request
const request = await requestPromise;

// Assert on the request
expect(request.headers.get("Authorization")).toBeDefined();

Waiting for a request on the client only or the server only

Similar to Client.route you can scope waiting for requests to the client, server, or both. The default behavior is to wait for requests on both the client and the server. The resolved request is the first request to be made.

const requestPromise = client.waitForRequest("**/api", {
// Allows you to scope waiting for requests to the client, server, or both.
// "server-only" | "client-only" | "both"
type: "client-only",
});

// Run code that triggers the request, i.e. loading a page

// Await the request
const request = await requestPromise;

// Assert on the request
expect(request.headers.get("Authorization")).toBeDefined();