自定义请求谓词

默认情况下,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)
  }
}
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.