自定义请求谓词
默认情况下,MSW 为你提供了基于方法和路径(对于 HTTP 请求)或操作类型和名称(对于 GraphQL 请求)拦截请求的方法。但是,你可以创建自定义匹配逻辑以根据其他条件拦截请求,例如:
¥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:
-
拦截具有
foo
查询参数的请求;¥Intercept a request that has a
foo
query parameter; -
拦截具有
bar
属性的 JSON 请求主体的请求。¥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
你可以使用 高阶解析器 函数实现自定义请求谓词。在下面的例子中,我们将创建一个 withSearchParams
函数,它将帮助我们根据请求的查询参数匹配满足自定义 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)
}
}
resolver
参数是我们在使用时将指定的实际响应解析器。围绕它的逻辑决定何时调用它,允许有条件的响应解析。¥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.
然后我们可以在任意地方使用 withSearchParams
函数代替响应解析器:
¥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
实现自定义请求主体谓词与查询谓词没有什么不同。我们将创建一个 withJsonBody
函数,它将提供匹配逻辑并有条件地调用 resolver
。
¥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)
}
}
确保在读取请求主体之前克隆请求。如果没有,你将无法在 resolver
中阅读它。
¥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
对于更高级的场景,请考虑实现自定义请求处理程序。你可以通过扩展从库中导出的 RequestHandler
类来做到这一点。
¥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.