- Introduction
- Getting started
- Philosophy
- Comparison
- Limitations
- Debugging runbook
- FAQ
- Basics
- Concepts
- Network behavior
- Integrations
- API
- CLI
- Best practices
- Recipes
- Cookies
- Query parameters
- Response patching
- Polling
- Streaming
- Network errors
- File uploads
- Responding with binary
- Custom worker script location
- Global response delay
- GraphQL query batching
- Higher-order resolver
- Keeping mocks in sync
- Merging Service Workers
- Mock GraphQL schema
- Using CDN
- Using custom "homepage" property
- Using local HTTPS
Custom request predicate
By default, MSW gives you the means to intercept requests based on their method and path (for HTTP requests) or their operation kind and name (for GraphQL requests). You can, however, create a custom matching logic to intercept requests based on other criteria, for example:
- Intercept a request that has a
foo
query parameter; - Intercept a request that has a JSON request body with a
bar
property.
Let’s implement both of these custom request predicates.
Query parameter predicate
You can implement a custom request predicate using a higher-order resolver function. In the example below, we will create a withSearchParams
function that will help us match requests that satisfy a custom predicate
based on the request’s query parameters.
// withSearchParams.js
import { passthrough } from 'msw'
export function withSearchParams(predicate, resolver) {
return (args) => {
const { request } = args
const url = new URL(request.url)
if (!predicate(url.searchParams)) {
return passthrough()
}
return resolver(args)
}
}
The
resolver
argument is the actual response resolver we will specify upon usage. The logic around it determines when to call it, allowing for conditional response resolution.
We can then use the withSearchParams
function instead of the response resolver anywhere we wish:
// handlers.js
import { http, HttpResponse } from 'msw'
import { withSearchParams } from './withSearchParams'
export const handlers = [
http.get(
'/user',
withSearchParams(
// Only match "GET /user" requests that have
// the "userId" query parameter present.
(params) => params.has('userId'),
({ request, params, cookies }) => {
return HttpResponse.json({
name: 'John Maverick',
})
}
)
),
]
Request body predicate
Implementing a custom request body predicate is no different from the query predicate. We will create a withJsonBody
function that will provide the matching logic and call the resolver
conditionally.
// withJsonBody.js
import isEqual from 'lodash.isequal'
export function withJsonBody(expectedBody, resolver) {
return async (args) => {
const { request } = args
// Ignore requests that have a non-JSON body.
const contentType = request.headers.get('Content-Type') || ''
if (!contentType.includes('application/json')) {
return
}
// Clone the request and read it as JSON.
const actualBody = await request.clone().json()
// Compare two objects using "lodash".
if (!isEqual(actualBody, expectedBody)) {
return
}
return resolver(args)
}
}
Make sure to clone the request before reading its body. If you don’t, you
won’t be able to read it in the resolver
.
http.post(
'/user',
// Only match "POST /user" requests that have the
// "id" property of their body equal to "abc-123".
withJsonBody(
{
id: 'abc-123',
},
({ request, params, cookies }) => {
return HttpResponse.json({}, { status: 201 })
}
)
)
Advanced
For more advanced scenarios, consider implementing a custom request handler. You can do that by extending the RequestHandler
class exported from the library.
RequestHandler
API reference for the `RequestHandler` class.