Playwright 网络拦截

Playwright 网络拦截(Route & Request Interception)(2025 年最新版)

网络拦截是 Playwright 最强大的功能之一,允许你拦截、修改、mock 或中止浏览器发出的任何网络请求(XHR、fetch、API 调用、图片、CSS 等)。常用于:

  • Mock API 响应(加速测试、避免真实后端依赖)
  • 测试错误场景(404、500、超时)
  • 修改请求头/参数
  • 模拟网络延迟或离线
  • 捕获 API 数据进行断言

Playwright 使用 page.route()route.handler() 实现拦截,支持通配符匹配。

1. 基本用法:拦截并 Mock 响应

// tests/mock-api.spec.ts
import { test, expect } from '@playwright/test';

test('Mock API 返回固定数据', async ({ page }) => {
  // 拦截所有 /api/users 请求
  await page.route('**/api/users', async route => {
    // Mock 一个成功的 JSON 响应
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      headers: { 'Access-Control-Allow-Origin': '*' },  // 可选:处理 CORS
      body: JSON.stringify([
        { id: 1, name: 'Mock 用户1' },
        { id: 2, name: 'Mock 用户2' },
      ]),
    });
  });

  await page.goto('https://your-app.com/users');

  // 页面会显示我们 mock 的数据
  await expect(page.getByRole('heading')).toHaveText('用户列表');
  await expect(page.getByText('Mock 用户1')).toBeVisible();
});

2. 常见拦截模式

场景代码示例说明
继续原请求(不修改)await route.continue();默认行为,常用于日志记录
修改请求(添加头/参数)“`await
中止请求(模拟失败)await route.abort('failed');await route.abort();触发 network error
模拟错误响应await route.fulfill({<br> status: 500,<br> body: 'Server Error'<br>});返回 4xx/5xx
重定向await route.fulfill({ status: 301, headers: { location: '/new-url' } });模拟重定向
模拟网络延迟await page.route('**/*', async route => {<br> await new Promise(r => setTimeout(r, 2000)); // 延迟 2s<br> await route.continue();<br>});测试 loading 状态
拦截特定类型资源await page.route('**/*.{png,jpg,jpeg}', route => route.abort());阻塞图片加载(加速测试)

3. 高级:根据请求动态决定

await page.route('**/api/**', async route => {
  const method = route.request().method();

  if (method === 'GET' && route.request().url().includes('users/1')) {
    await route.fulfill({
      json: { id: 1, name: '特殊用户', vip: true }
    });  // shorthand for JSON
  } else if (method === 'POST') {
    // 记录请求体用于断言
    const postData = route.request().postDataJSON();
    console.log('收到 POST 数据:', postData);
    await route.fulfill({ status: 201, json: { success: true } });
  } else {
    await route.continue();
  }
});

4. 捕获响应进行断言

// 等待特定响应并验证
const [response] = await Promise.all([
  page.waitForResponse('**/api/login'),
  page.getByRole('button', { name: '登录' }).click(),
]);

expect(response.status()).toBe(200);
const json = await response.json();
expect(json.token).toBeTruthy();

5. 拦截 WebSocket(Playwright v1.30+ 支持)

await page.route('wss://example.com/socket', route => {
  // WebSocket 拦截目前有限制,通常用 route.continue() + page.on('websocket')
  route.continue();
});

page.on('websocket', ws => {
  console.log(`WebSocket 打开: ${ws.url()}`);
  ws.on('framesent', frame => console.log('发送:', frame));
});

6. Python 版示例(Mock API)

def handle_route(route):
    if "api/users" in route.request.url:
        route.fulfill(
            status=200,
            content_type="application/json",
            body='[{"id":1,"name":"Mock 用户"}]'
        )
    else:
        route.continue_()

page.route("**/api/**", handle_route)
page.goto("https://your-app.com")

最佳实践总结

  • 匹配规则:使用 **/ 通配符(如 **/api/**)覆盖所有子路径。
  • 优先级:先定义具体路由,后定义通用路由(后定义的优先)。
  • 清理:测试结束无需手动 unroute,Playwright 会自动清理。
  • 生产测试:结合 route.fulfill() mock 不稳定第三方 API。
  • 调试:用 page.on('request')page.on('response') 打印日志观察拦截效果。

网络拦截能让你完全掌控测试环境,避免外部依赖导致的 flaky 测试。下一步建议:实现一个完整的登录流程,使用网络拦截 mock 登录 API 并验证返回 token。

需要更复杂的场景(如文件下载拦截、GraphQL Mock、多环境切换),随时告诉我!

文章已创建 3420

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部