MSW 处理器
REST 处理器
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/api/users', () => {
return HttpResponse.json([
{ id: 1, name: '张三', email: '[email protected]' },
{ id: 2, name: '李四', email: '[email protected]' },
])
}),
http.get('/api/users/:id', ({ params }) => {
const { id } = params
if (id === '999') {
return new HttpResponse(null, { status: 404 })
}
return HttpResponse.json({ id: Number(id), name: '张三' })
}),
http.post('/api/users', async ({ request }) => {
const body = await request.json()
return HttpResponse.json({ id: 3, ...body }, { status: 201 })
}),
]
GraphQL 处理器
import { graphql, HttpResponse } from 'msw'
export const handlers = [
graphql.query('GetUser', ({ variables }) => {
return HttpResponse.json({
data: {
user: { id: variables.id, name: '张三' },
},
})
}),
graphql.mutation('CreateUser', async ({ variables }) => {
return HttpResponse.json({
data: {
createUser: { id: 99, ...variables },
},
})
}),
]
Node.js 配置 — Jest 集成
// src/mocks/server.ts
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
export const server = setupServer(...handlers)
// jest.setup.ts
import { server } from './src/mocks/server'
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
// 在测试中覆盖处理器
test('API 失败时显示错误', async () => {
server.use(
http.get('/api/users', () => {
return HttpResponse.json({ error: '服务器错误' }, { status: 500 })
})
)
render(<UserList />)
await waitFor(() => screen.getByText('加载用户失败'))
})
高级响应解析器
import { http, HttpResponse, delay } from 'msw'
export const handlers = [
// 模拟延迟
http.get('/api/slow', async () => {
await delay(1500)
return HttpResponse.json({ data: '慢响应' })
}),
// 自定义响应头
http.get('/api/data', () => {
return new HttpResponse(JSON.stringify({ items: [] }), {
status: 200,
headers: { 'X-Total-Count': '42' },
})
}),
// 模拟网络错误
http.get('/api/broken', () => {
return HttpResponse.error()
}),
// 读取查询参数
http.get('/api/search', ({ request }) => {
const url = new URL(request.url)
const q = url.searchParams.get('q')
return HttpResponse.json([{ id: 1, title: `${q} 的搜索结果` }])
}),
]
浏览器配置
// npx msw init public/ --save
// src/mocks/browser.ts
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'
export const worker = setupWorker(...handlers)
// src/main.tsx
async function enableMocking() {
if (process.env.NODE_ENV !== 'development') return
const { worker } = await import('./mocks/browser')
return worker.start({ onUnhandledRequest: 'warn' })
}
enableMocking().then(() => {
ReactDOM.createRoot(document.getElementById('root')!).render(<App />)
})
Browser vs Node 对比
| 环境 | 配置方式 | 适用场景 |
|---|---|---|
| 浏览器 | setupWorker + Service Worker | 开发环境、Storybook |
| Node.js | setupServer + 拦截器 | Jest 单元/集成测试 |
| Playwright | page.route() 或 HTTP 中间件 | E2E 测试 |