- 前端
- 富文本
- UI组件
- AI 应用
【免费下载链接】BlockNote
A React Rich Text Editor that's block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.
本指南以 request-mocking.md 为骨架,系统讲解 playwright-cli 的网络请求拦截能力:如何用route命令快速 mock、按 URL 模式匹配、以及通过run-code编写任意复杂的请求处理逻辑。在本仓库(BlockNote)中,这些能力直接服务于 tests/src/end-to-end 下的端到端测试,例如在 images.test.tsx 中通过外部图片 URL 断言图片块的嵌入行为——当真实网络不可用或需要稳定复现时,拦截与 mock 就是让测试确定性的关键手段。读完本文,你将掌握 CLI 级别与代码级别两套请求操控方案,并能把它们落地到自己的 Playwright 测试流程中。
概述:为什么需要请求 Mocking
端到端测试与人工验证中最不稳定的因素往往不是前端逻辑,而是网络:图片加载失败、接口延迟、服务端 500、登录态过期……任何一次外部依赖波动都可能让一次本应通过的验证功亏一篑。请求 Mocking(Request Mocking)的核心思想是:在浏览器发起网络请求之前把它拦截下来,然后按需伪造、修改或直接丢弃,让被测页面始终面对一个确定性的"网络环境"。
playwright-cli 为这一需求提供了两层能力:
- CLI 命令层:
route/route-list/unroute,适合快速、临时、低成本的拦截与替换; - 代码层:
run-code+page.route(),适合需要读取请求体、按条件分支、修改真实响应或注入延迟的复杂场景。
快速上手:route 命令基础用法
playwright-cli route是最直接的拦截入口,它的通用形态是:
playwright-cli route <URL模式> [选项]用自定义状态码 mock
最常见的需求是模拟接口失败。例如让所有 jpg 图片请求返回 404,用于验证图片块的降级渲染:
playwright-cli route "**/*.jpg" --status=404用 JSON 体 mock
模拟接口返回数据,需要同时指定响应体和 Content-Type。下面的命令让所有/api/users请求固定返回两条用户记录:
playwright-cli route "**/api/users" --body='[{"id":1,"name":"Alice"}]' --content-type=application/json注意:当--body提供 JSON 字符串时,务必同时给出--content-type=application/json,否则浏览器端按默认 MIME 处理可能解析异常。
带自定义响应头 mock
对于需要验证响应头行为的场景,用--header追加自定义头:
playwright-cli route "**/api/data" --body='{"ok":true}' --header="X-Custom: value"--header可重复使用,以注入多个响应头。
从请求中剥离敏感头
真实环境下浏览器会带上 Cookie、Authorization 等凭据头。如果要模拟"未登录/匿名访问"场景,可以按头名剥离:
playwright-cli route "**/*" --remove-header=cookie,authorization多个头名用逗号分隔,该命令会拦截所有请求并移除指定的请求头。
查看与清理路由
- 列出当前会话中所有生效的路由:
playwright-cli route-list- 删除某一条路由:
playwright-cli unroute "**/*.jpg"- 不带参数删除全部路由:
playwright-cli unrouteURL 模式语法
route的 URL 模式基于 glob 风格通配符,正确理解它才能精确命中目标请求:
**/api/users - 精确匹配路径(不限域名与端口) **/api/*/details - 路径中的单段通配 **/*.{png,jpg,jpeg} - 匹配多种文件扩展名 **/search?q=* - 匹配带查询参数的地址要点说明:
**匹配任意层级的路径前缀,因此**/api/users可以同时命中https://example.com/api/users与https://api.example.com/users;*只匹配路径中的单段内容;{a,b,c}花括号用于枚举扩展名等备选值;- 模式同样适用于查询字符串(如
**/search?q=*),可按参数形态精确圈定拦截范围。
在 SKILL.md 的 Network 一节(见 .claude/skills/playwright-cli/SKILL.md)中,还给出了按完整域名限定的示例:playwright-cli route "https://api.example.com/**" --body='{"mock": true}',说明模式既可以松散(**前缀)也可以严格(完整域名)。
进阶:run-code 驱动的动态 Mock
CLI 选项适合"静态替换",但当拦截逻辑依赖请求内容、真实响应或时间时,就需要完整调用 Playwright 的page.route()API。run-code的通用语法如下(详见 running-code.md):
playwright-cli run-code "async page => { // 此处可访问 page 与 page.context() }"代码必须是一个单一的函数表达式(会被包在(...)中求值),不支持 import/export/require 语法;也可以用--filename=script.js从文件加载。
按请求内容条件返回
下面的示例拦截登录接口,检查请求体中的用户名:admin用户返回伪造 token,其他用户一律 401。这是"读取请求体 → 分支处理"的典型模式:
playwright-cli run-code "async page => { await page.route('**/api/login', route => { const body = route.request().postDataJSON(); if (body.username === 'admin') { route.fulfill({ body: JSON.stringify({ token: 'mock-token' }) }); } else { route.fulfill({ status: 401, body: JSON.stringify({ error: 'Invalid' }) }); } }); }"修改真实响应(响应透传 + 篡改)
不想完全伪造接口,而是"请求照发、回来改一改",可以使用route.fetch()先取真实响应,再修改后fulfill:
playwright-cli run-code "async page => { await page.route('**/api/user', async route => { const response = await route.fetch(); const json = await response.json(); json.isPremium = true; await route.fulfill({ response, json }); }); }"route.fulfill({ response, json })会把原始响应的状态码与头保留下来,仅替换响应体,非常适合在保留真实接口语义的前提下做 A/B 式注入。
模拟网络故障
直接放弃请求并返回一个"网络层错误",可用于验证应用的错误提示与重试逻辑:
playwright-cli run-code "async page => { await page.route('**/api/offline', route => route.abort('internetdisconnected')); }" # 可选错误码: # connectionrefused - 连接被拒绝 # timedout - 连接超时 # connectionreset - 连接被重置 # internetdisconnected - 模拟断网注入延迟
模拟慢接口,验证 loading 态与超时处理:
playwright-cli run-code "async page => { await page.route('**/api/slow', async route => { await new Promise(r => setTimeout(r, 3000)); route.fulfill({ body: JSON.stringify({ data: 'loaded' }) }); }); }"在本仓库中的落地场景
本仓库(BlockNote)的端到端测试位于 tests/src/end-to-end,基于 vitest-browser-react 渲染真实编辑器组件,并大量断言截图与文档快照。以图片块测试 images.test.tsx 为例,其中嵌入测试固定使用外部图床地址:
const IMAGE_EMBED_URL = "https://placehold.co/800x540.png";随后通过waitForSelector(\img[src="${IMAGE_EMBED_URL}"]`)` 等待图片真正加载完成(images.test.tsx)。这类依赖外部网络的断言正是请求 Mocking 的典型适用场景:在无外网或 CI 网络受限的环境下,可以用
playwright-cli route "**/placehold.co/**" --body='<svg .../>' --content-type=image/svg+xml或借助run-code拦截后返回一张本地图片字节,让图片块渲染路径在不依赖公网的前提下被稳定验证。同理,AI 接口、协作同步、文件上传等依赖后端服务的测试(见 tests/src/end-to-end/ai 与 tests/src/end-to-end/comments/comments.test.tsx),都可以先route出固定响应,再逐步替换为真实接口回归。
从更广的视角看,拦截能力还能与 playwright-tests.md 描述的调试流程配合:PLAYWRIGHT_HTML_OPEN=never npx playwright test --debug=cli启动后,用playwright-cli attach连上测试会话,在逐步探索页面时用route动态改写网络行为,从而隔离"应用 bug"与"网络环境问题"。
常见问题与注意事项
- route 作用范围:
route作用于当前浏览器会话内的全部页面与 iframe,route-list可随时查看已注册的规则,避免规则叠加造成意外拦截。 --body与--content-type需成对出现:伪造 JSON 时忘记指定 Content-Type 会导致响应被浏览器按错误类型解析。run-code代码限制:函数体内不能使用 import/export/require;复杂逻辑建议写成独立脚本文件后用--filename加载,便于维护。route.fetch()的用途边界:它发起的是真实网络请求,仅适合网络可用、且需要保留真实语义的场景;纯离线环境请直接用route.fulfill伪造。- 调试建议:先用
route-list确认规则已注册,再配合 running-code.md 中的console/requests命令观察实际请求是否被命中。
小结
请求 Mocking 把"不可控的网络"变成"可控的测试夹具":route系列命令负责快速替换与清理,run-code负责条件分支、响应篡改、故障注入与延迟模拟。两者结合 URL 模式语法,足以覆盖从"图片 404"到"登录鉴权分支"再到"断网演练"的绝大多数验证场景。配合本仓库的端到端测试体系,你可以在无外网、弱网或后端未就绪时,依然对 BlockNote 编辑器(图片、AI、协作等模块)进行确定性验证。
- 前端
- 富文本
- UI组件
- AI 应用
【免费下载链接】BlockNote
A React Rich Text Editor that's block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.
相关推荐
Sanity 仓库 Playwright 请求 Mock 完整指南:playwright-cli route 与 run-code 的拦截、伪造与故障注入实战
Sanity 仓库 Playwright 请求 Mock 完整指南:playwright cli route 与 run code 的拦截、伪造与故障注入实战
CMS前端抖音视频无水印批量下载:从单条链接到定时增量抓主页
抖音视频无水印批量下载:从单条链接到定时增量抓主页 你每周要攒一批竞品账号的抖音视频,手工流程是这样的:点开主页、逐条右键另存为、挑出带水印的再换源、给文件重命
网页爬虫CLIPuppeteer Page.setRequestInterception() 全解析:开启请求拦截、阻塞与改写网络请求的完整指南
Puppeteer Page.setRequestInterception 全解析:开启请求拦截、阻塞与改写网络请求的完整指南 网络拦截是浏览器自动化中高频使用
浏览器控制测试网页爬虫开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考