网络行为覆盖

网络的性质可能非常动态,这使得在固定的请求处理程序列表中完整描述它具有挑战性。MSW 为你提供使用指定 .use() API 覆盖任何特定网络行为的方法。

¥The nature of the network can be highly dynamic, which makes it challenging to describe it completely in a fixed list of request handlers. MSW provides you the means to override any particular network behavior using the designated .use() API.

使用 .use(),你可以将任何请求处理程序列表添加到提供给 setupWorker()/setupServer() 的初始请求处理程序之前,使它们在处理请求时优先。由于这是一个运行时 API,你可以在启用 API 模拟后调用它,例如,在单独测试的基础上。

¥With the .use(), you can prepend any list of request handlers to the initial request handlers provided to setupWorker()/setupServer(), making them take priority when handling requests. Since this is a runtime API, you can invoke it after the API mocking has been enabled, for example, on the individual test basis.

初始与运行时处理程序

¥Initial vs runtime handlers

提供给 setupWorker()/setupServer() 函数调用的请求处理程序列表称为初始请求处理程序。

¥The list of request handlers provided to the setupWorker()/setupServer() function calls is called initial request handlers.

import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
 
const server = setupServer(
  // These are the initial request handlers.
  http.get('/resource', () => {
    return HttpResponse.text('Fallback')
  })
)

在此点之后添加的任何请求处理程序都称为运行时请求处理程序。这是你使用 .use() 函数添加的请求处理程序类型:

¥Any request handlers added past this point are referred to as runtime request handlers. This is the kind of request handlers you are adding with the .use() function:

import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
 
const server = setupServer(
  // These are the initial request handlers.
  http.get('/resource', () => {
    return HttpResponse.text('Fallback')
  })
)
 
server.use(
  // These are the runtime request handlers.
  http.post('/login', () => {
    return new HttpResponse()
  })
)

这种区别很重要,因为你可以添加和耗尽运行时请求处理程序,同时依赖初始处理程序作为后备网络描述。

¥This distinction is important because you can add and exhause runtime request handlers while relying on the initial handlers as the fallback network description.

网络覆盖类型

¥Network override types

.use() API 允许你根据需要建立不同类型的网络覆盖。

¥The .use() API allow you to establish different types of network overrides depending on your needs.

永久覆盖

¥Permanent override

默认情况下,调用 .use() 将创建永久覆盖。

¥By default, calling .use() will create a permanent override.

import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
 
const server = setupServer(
  http.get('/resource', () => {
    return HttpResponse.text('Fallback')
  })
)
 
server.use(
  http.get('/resource', () => {
    return HttpResponse.text('Override')
  })
)

在此示例中,GET /resource 请求将始终收到 "Override" 纯文本响应,因为附加 .use() 的请求处理程序优先。

¥In this example, the GET /resource request will always receive the "Override" plain text response because the request handler attached with .use() takes precedence.

一次性覆盖

¥One-time override

你可以通过在任何请求处理程序上提供 { once: true } 选项来添加一次性网络覆盖。

¥You can add a one-time network override by providing the { once: true } option on any request handler.

const server = setupServer(
  http.get('/resource', () => {
    return HttpResponse.text('Fallback')
  })
)
 
server.use(
  http.get(
    '/resource',
    () => {
      return HttpResponse.text('One-time override')
    },
    { once: true }
  )
)

使用此设置,只有第一个 GET /resource 请求将收到 "One-time override" 纯文本响应。一旦使用覆盖请求处理程序,它就会将自身标记为已耗尽,并且不会再影响传出流量。对 GET /resource 的任何后续请求都将根据提供给 setupServer() 调用的初始请求处理程序接收 "Fallback" 纯文本响应。

¥With this setup, only the first GET /resource request will receive the "One-time override" plain text response. As soon as the override request handler gets used, it will mark itself as exhausted, and won’t affect the outgoing traffic anymore. Any subsequent requests to GET /resource will receive the "Fallback" plain text response as per the initial request handler provided to the setupServer() call.

重置请求处理程序

¥Resetting request handlers

你可以通过在调用 .use() 的同一 worker/server 对象上调用 .resetHandlers() 方法,随时删除通过 .use() 添加的任何请求处理程序。

¥You can remove any request handlers added via .use() at any point in time by calling the .resetHandlers() method on the same worker/server object that called .use().

这对于清理在单个测试中引入的任何运行时请求处理程序特别有用,这样它们就不会影响不相关的测试。

¥This is particularly useful to clean up any runtime request handlers introduced in individual tests so they don’t affect unrelated tests.

import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
 
const server = setupServer(
  http.get('/user', () => {
    return HttpResponse.json({ name: 'John Maverick' })
  })
)
 
beforeAll(() => {
  server.listen()
})
 
afterEach(() => {
  // This will remove any runtime request handlers
  // after each test, ensuring isolated network behavior.
  server.resetHandlers()
})
 
afterAll(() => {
  server.close()
})
 
it('handles a 500 server error response', () => {
  server.use(
    http.get('/user', () => {
      return new HttpResponse(null, { status: 500 })
    })
  )
 
  // Your application in this test will always receive
  // a 500 error response when requesting "GET /user".
})
 
it('displays a greeting message', () => {
  // This test, however, will use the network description
  // as provided in the initial request handlers of the
  // "setupServer()" call above. This means a 200 OK
  // application/json response to the "GET /user" requests.
})

重置初始请求处理程序

¥Resetting initial request handlers

如果你提供下一个初始处理程序列表作为 .resetHandlers() 函数调用的参数,则可以使用 .resetHandlers() 方法替换初始请求处理程序并引入全新的网络描述。

¥You can use the .resetHandlers() method to replace the initial request handlers and introduce entirely new network description if you provide a list of next initial handlers as the argument to the .resetHandlers() function call.

const server = setupServer(
  http.get('/resource', () => {
    return HttpResponse.text('Fallback')
  })
)
 
server.resetHandlers(
  http.post('/login', () => {
    return new HttpResponse()
  })
)

在此示例中,一旦你使用下一个初始请求处理程序列表调用 .resetHandlers() 方法,任何先前的请求处理程序(包括初始和运行时)都将被清除。这意味着 GET /resource 请求将没有请求处理程序,只有 POST /login 请求。

¥In this example, once you call the .resetHandlers() method with the list of next initial request handlers, any previous request handlers, both initial and runtime, will be wiped out. This means that there will be no request handler for the GET /resource request, only for the POST /login request.

通常不建议改变初始请求处理程序,因为它会损害网络的可预测性。但是,在某些情况下,它可能很有用,例如在浏览器中开发时测试不同的行为。

¥Mutating the initial request handlers is generally not recommended because it harms the predictability of the network. It can be useful, however, in certain situations, like testing different behaviors while developing in the browser.

恢复请求处理程序

¥Restoring request handlers

你可以通过在 worker/server 对象上调用 .restoreHandlers() 来恢复任何使用的一次性请求处理程序。

¥You can restore any used one-time request handler by calling .restoreHandlers() on the worker/server object.

const server = setupServer(
  http.get('/resource', () => {
    return HttpResponse.text('Fallback')
  })
)
 
server.use(
  http.get(
    '/resource',
    () => {
      return HttpResponse.text('One-time')
    },
    { once: true }
  )
)
 
await fetch('/resource')
// 200 OK
// "One-time"
 
await fetch('/resource')
// 200 OK
// "Fallback"
 
server.restoreHandlers()
 
await fetch('/resource')
// 200 OK
// "One-time"
 
await fetch('/resource')
// 200 OK
// "Fallback"

请注意,如果你使用 重置运行时请求处理程序,它们将被删除,然后才能恢复。

¥Note that if you reset the runtime request handlers, they will be removed before they can be restored.