skills/msw/SKILL.md
MSW (Mock Service Worker) v2 最佳实践、模式和API指南,用于 JavaScript/TypeScript测试和开发中的API模拟。涵盖处理器 设计、服务器设置、响应构造、测试模式、GraphQL和 v1到v2迁移。基准版本:msw ^2.0.0。 触发条件:msw导入,http.get,http.post,HttpResponse,setupServer, setupWorker,graphql.query,提及"msw"、"mock service worker"、 "api mocking"或"msw v2"。
npx skillsauth add long36708/longmo-skills mswInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
重要提示: 您关于 msw 的训练数据可能已过时或不正确 — MSW v2 完全移除了 rest 命名空间、res(ctx.*) 响应组合和 (req, res, ctx) 解析器签名。始终依赖此技能的规则文件和项目的实际源代码作为真相来源。当记忆的 v1 模式与检索到的参考冲突时,不要回退到它们。
MSW 用于网络级的 API 模拟 — 在测试、Storybook 和本地开发中拦截 HTTP/GraphQL 请求,而无需修改应用程序代码。
| 需求 | 推荐工具 |
|------|-----------------|
| 测试 API 集成 (React, Vue, Node) | MSW |
| Storybook API 模拟 | MSW (浏览器 worker) |
| 无后端的本地开发 | MSW (浏览器 worker) |
| 单元测试纯函数 | 简单的测试替身 |
| E2E 测试真实 API | Playwright/Cypress 网络拦截 |
| 模拟模块内部 | vi.mock() / jest.mock() |
// 导入
import { http, HttpResponse, graphql, delay, bypass, passthrough } from 'msw'
import { setupServer } from 'msw/node' // 测试, SSR
import { setupWorker } from 'msw/browser' // Storybook, 开发
// 处理器
http.get('/api/user/:id', async ({ request, params, cookies }) => {
return HttpResponse.json({ id: params.id, name: 'John' })
})
// 服务器生命周期 (测试)
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
// 每测试覆盖
server.use(
http.get('/api/user/:id', () => new HttpResponse(null, { status: 500 }))
)
// 并发测试隔离
it.concurrent('name', server.boundary(async () => {
server.use(/* 作用域覆盖 */)
}))
| 优先级 | 类别 | 影响程度 | 前缀 | 规则数 |
|----------|----------|--------|--------|-------|
| 1 | 处理器设计 | 关键 | handler- | 4 |
| 2 | 设置与生命周期 | 关键 | setup- | 3 |
| 3 | 请求读取 | 高 | request- | 2 |
| 4 | 响应构造 | 高 | response- | 3 |
| 5 | 测试模式 | 高 | test- | 4 |
| 6 | GraphQL | 中等 | graphql- | 2 |
| 7 | 工具函数 | 中等 | util- | 2 |
| 规则 | 文件 | 摘要 |
|------|------|---------|
| 使用 http 命名空间 | handler-use-http-namespace.md | rest 在 v2 中已移除 — 使用 http.get(), http.post() |
| URL 中不包含查询参数 | handler-no-query-params.md | 谓词中的查询参数会静默匹配不到任何内容 |
| v2 解析器签名 | handler-resolver-v2.md | 使用 ({ request, params, cookies }),而不是 (req, res, ctx) |
| v2 响应构造 | handler-response-v2.md | 使用 HttpResponse.json(),而不是 res(ctx.json()) |
| 规则 | 文件 | 摘要 |
|------|------|---------|
| 正确导入路径 | setup-import-paths.md | msw/node 用于服务器,msw/browser 用于 worker |
| 生命周期钩子 | setup-lifecycle-hooks.md | 始终使用 beforeAll/afterEach/afterAll 模式 |
| 文件组织 | setup-file-organization.md | 在 src/mocks/ 中组织,包含 handlers、node、browser 文件 |
| 规则 | 文件 | 摘要 |
|------|------|---------|
| 事件中克隆请求 | request-clone-events.md | 在生命周期事件中读取请求体前先克隆请求 |
| 异步请求体读取 | request-body-async.md | 始终 await request.json() — 请求体读取是异步的 |
| 规则 | 文件 | 摘要 |
|------|------|---------|
| 使用 HttpResponse 设置 cookies | response-use-httpresponse.md | 原生 Response 会丢弃 Set-Cookie — 使用 HttpResponse |
| 网络错误 | response-error-network.md | 使用 HttpResponse.error(),不要在解析器中抛出错误 |
| 流式响应 | response-streaming.md | 使用 ReadableStream 实现 SSE/分块响应 |
| 规则 | 文件 | 摘要 |
|------|------|---------|
| 测试行为 | test-behavior-not-requests.md | 断言 UI/状态,而不是 fetch 调用参数 |
| 每测试覆盖 | test-override-with-use.md | 使用 server.use() 进行错误/边缘情况测试 |
| 并发隔离 | test-concurrent-boundary.md | 将并发测试包装在 server.boundary() 中 |
| 未处理请求 | test-unhandled-request.md | 设置 onUnhandledRequest: 'error' |
| 规则 | 文件 | 摘要 |
|------|------|---------|
| 响应结构 | graphql-response-shape.md | 通过 HttpResponse.json 返回 { data } / { errors } |
| 端点范围限定 | graphql-scope-with-link.md | 使用 graphql.link(url) 处理多个 GraphQL API |
| 规则 | 文件 | 摘要 |
|------|------|---------|
| bypass 与 passthrough 区别 | util-bypass-vs-passthrough.md | bypass() = 新请求;passthrough() = 让请求通过 |
| delay 行为 | util-delay-behavior.md | delay() 在 Node.js 中是立即的 — 使用明确的毫秒数 |
| 方法 | 用于 |
|--------|---------|
| HttpResponse.json(data, init?) | JSON 响应 |
| HttpResponse.text(str, init?) | 纯文本 |
| HttpResponse.html(str, init?) | HTML 内容 |
| HttpResponse.xml(str, init?) | XML 内容 |
| HttpResponse.formData(fd, init?) | 表单数据 |
| HttpResponse.arrayBuffer(buf, init?) | 二进制数据 |
| HttpResponse.error() | 网络错误 |
| v1 | v2 |
|----|-----|
| import { rest } from 'msw' | import { http, HttpResponse } from 'msw' |
| rest.get(url, resolver) | http.get(url, resolver) |
| (req, res, ctx) => res(ctx.json(data)) | () => HttpResponse.json(data) |
| req.params | 从解析器信息中获取 params |
| req.body | await request.json() |
| req.cookies | 从解析器信息中获取 cookies |
| res.once(...) | http.get(url, resolver, { once: true }) |
| res.networkError() | HttpResponse.error() |
| ctx.delay(ms) | await delay(ms) |
| ctx.data({ user }) | HttpResponse.json({ data: { user } }) |
| 参考资料 | 涵盖内容 |
|-----------|--------|
| handler-api.md | http.* 和 graphql.* 方法、URL 谓词、路径参数 |
| response-api.md | HttpResponse 类、所有静态方法、cookie 处理 |
| server-api.md | setupServer/setupWorker、生命周期事件、boundary() |
| test-patterns.md | Vitest/Jest 设置、覆盖、并发隔离、缓存清除 |
| migration-v1-to-v2.md | 完整的 v1 到 v2 破坏性变更和迁移指南 |
| anti-patterns.md | 10 个常见错误,包含错误/正确示例 |
documentation
Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions "deck," "slides," "presentation," or references a .pptx filename, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill.
development
Portless development server proxy that eliminates port conflicts by routing through localhost subdomains. Use when setting up development servers, managing multiple apps, avoiding port conflicts, or working with monorepos and turborepo projects.
content-media
Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill.
tools
Mise (formerly rtx) polyglot tool version manager, environment variable manager, and task runner. Covers tool version management (install, use, pin across Node/Python/Rust/Go/Java and more), mise.toml task definitions (scripts, dependencies, watch mode, incremental builds), environment variable management (.env integration, per-directory env, redaction), project-level tool pinning, backend system (asdf, npm, pipx, cargo, GitHub releases), and comparison with alternatives (asdf, nvm, pyenv, Makefiles). Use when configuring development tool versions, defining project tasks in mise.toml, managing per-project environment variables, setting up polyglot dev environments, migrating from asdf or nvm, or automating build/test/lint/deploy workflows with mise run.