进阶使用

125 阅读2分钟

拦截请求

通过一个叫做**request handler**的函数实现请求拦截,即 `http.get(predicate, resolver)`
  • 参数predicate:【字符串|正则】需要拦截的目标请求地址
  • 参数resolver:【函数】决定如何处理拦截请求

mock响应

原生的Response

msw遵循fetch的规范,可以使用fetch原生的Response类,同时也可以支持Response实例,其中包括通过`Response.json()` or `Response.error()`这些方法创建的responses实例。
import { http } from 'msw'
export const handlers = [
  http.get('/resource', () => {
    // "text/plain" 类型
    return new Response('Hello world!')
  }),
]

使用msw的HttpResponse类【!!!推荐】

- 封装了许多原生的方法 - 支持mock的时候通过Set-Cookie头来模拟响应cookie
import { http, HttpResponse } from 'msw'
export const handlers = [
  http.get('/resource', () => {
    return HttpResponse.text('Hello world!')
  }),
]

模拟请求状态码和状态文案等

import { http, HttpResponse } from 'msw'
export const handlers = [
  http.get('/apples', () => {
    return new HttpResponse(null, {
      status: 404,
      statusText: 'Out Of Apples',
      headers:{
        'Set-Cookie': 'mySecret=abc-123',
        'X-Custom-Header': 'yes',
      }
    })
  }),
]

模拟响应体

response body类型:json、Blob, FormData, ReadableStream等
import { http, HttpResponse } from 'msw'
export const handlers = [
  http.post('/auth', () => {
    return HttpResponse.json({
      user: {
        id: 'abc-123',
        name: 'John Maverick',
      },
    })
  }),
]

模拟网络错误

使用 Response.error() 或者 HttpResponse.error()这些静态方法实现
import { http, HttpResponse } from 'msw'
export const handlers = [
  http.post('/checkout/cart', () => {
    return HttpResponse.error()
  }),
]

和ts搭配使用

所有处于http这个namespace的request handler都接受3个范型参数:

http.get<Params, RequestBodyType, ResponseBodyType, Path>(path, resolver)

  • Params:需要传给实际接口的请求参数
  • RequestBodyType:请求体
  • ResponseBodyType:实际接口返回的响应类型
import { http, HttpResponse } from 'msw'
type AddCommentParams = {
  postId: string
}
type AddCommentRequestBody = {
  author: User
  comment: string
}
type AddCommentResponseBody = {
  commentUrl: string
}
http.post<
  AddCommentParams,
  AddCommentRequestBody,
  AddCommentResponseBody,
  '/post/:postId'
>('/post/:postId', async ({ params, request }) => {
  const { postId } = params
  const commentData = await request.json()
  commentData.comment
  return HttpResponse.json({
    commentUrl: `/post/${postId}?commentId=${crypto.randomUUID()}`,
  })
})

request handler进阶使用

import { http, HttpResponseResolver, HttpResponse } from 'msw'
type SdkRequest = {
  transactionId: string
}
type SdkResponse = {
  transactionId: string
  data: { ok: boolean }
}
function handleSdkRequest(
  resolver: HttpResponseResolver<never, SdkRequest, SdkResponse>
) {
  return http.post('https://some-sdk.com/internal/request', resolver)
}
export const handlers = [
  handleSdkRequest(async ({ request }) => {
    const data = await request.json()
    //响应的json必须符合SdkResponse这个类型.
    return HttpResponse.json({
      //  request body被限制为SdkRequest
      transactionId: data.transactionId,
      data: { ok: true },
    })
  }),
]

response resolver的进阶使用

import {
  PathParams,
  DefaultBodyType,
  HttpResponseResolver,
  delay,
  http,
  HttpResponse,
} from 'msw'
function withDelay<
  Params extends PathParams,
  RequestBodyType extends DefaultBodyType,
  ResponseBodyType extends DefaultBodyType
>(durationMs: number, resolver: HttpResponseResolver<Params, RequestBodyType, ResponseBodyType>): HttpResponseResolver<Params, RequestBodyType, ResponseBodyType> {
  return async (...args) => {
    await delay(durationMs)
    return resolver(...args)
  }
}
export const handlers = [
  http.get<never, never, 'hello world'>(
    '/resource',
    withDelay(250, ({ request }) => {
      // The "ResponseBodyType" generic type provided
      // to the "http.get()" request handler propagates
      // through the custom "withDelay" response resolver.
      return HttpResponse.text('hello world')
    })
  ),
]