Skip to content

Playwright 网络拦截与 Mock

本章介绍如何使用 Playwright 拦截、修改和模拟网络请求,实现不依赖后端 API 的独立测试。


什么是网络拦截

网络拦截允许你在浏览器发起 HTTP 请求时进行干预。

你可以阻止请求、修改响应、返回模拟数据,让测试不依赖外部 API 或网络状态。


page.route() 拦截请求

page.route(url, handler) 用于拦截匹配指定 URL 模式的所有网络请求。

基本拦截

实例

javascript

test('拦截所有图片请求', async ({ page }) => {

  // 拦截所有 PNG 和 JPEG 图片

  await page.route('**/*.{png,jpg,jpeg}', route => route.abort());

  // 导航到页面(图片不会被加载)

  await page.goto('https://www.runoob.com/');

  // 页面可能加载更快,因为没有下载图片

});

URL 匹配模式支持以下格式:

模式示例说明
完整 URL'https://api.example.com/users'精确匹配
Glob 通配符'**/api/**'** 匹配任意路径
正则表达式/\/api\/v\d\/users/灵活匹配
函数url => url.includes('/api/')编程逻辑匹配

route.abort() 阻止请求

实例

javascript

test('阻止第三方分析脚本', async ({ page }) => {

  // 阻止 Google Analytics 等分析脚本

  await page.route('**/*analytics*', route => route.abort());

  // 阻止 CSS 文件

  await page.route('**/*.css', route => route.abort());

  await page.goto('https://www.runoob.com/');

  // 页面以无样式形式加载,但不影响功能测试

});

route.fulfill() 模拟响应

route.fulfill() 是最强大的 Mock 方法,可以返回任意自定义响应。

Mock JSON 数据

实例

javascript

test('Mock 用户列表 API', async ({ page }) => {

  // 拦截用户列表 API,返回模拟数据

  await page.route('**/api/users', async route => {

    await route.fulfill({

      status: 200,

      contentType: 'application/json',

      json: [

        { id: 1, name: 'runoob_user', email: 'user@runoob.com' },

        { id: 2, name: 'test_user', email: 'test@runoob.com' },

      ],

    });

  });

  await page.goto('https://www.runoob.com/users');

  // 页面会显示 Mock 数据而不是真实的 API 数据

});

Mock 错误响应

实例

javascript

test('测试 API 错误处理', async ({ page }) => {

  // 模拟 500 服务器错误

  await page.route('**/api/data', async route => {

    await route.fulfill({

      status: 500,

      contentType: 'application/json',

      json: { error: '服务器内部错误' },

    });

  });

  await page.goto('https://www.runoob.com/dashboard');

  // 验证错误提示是否正常显示

  await expect(page.getByText('服务器内部错误')).toBeVisible();

});

route.continue() 修改后继续

不是直接返回模拟数据,而是修改真实请求或响应后继续发送到服务器。

实例

javascript

test('修改请求头', async ({ page }) => {

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

    // 修改请求头,添加自定义 Header

    const headers = {

      ...request.headers(),

      'X-Custom-Header': 'RUNOOB-TEST',

    };

    await route.continue({ headers });

  });

  await page.goto('https://www.runoob.com/');

});

test('修改 POST 数据', async ({ page }) => {

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

    // 覆盖 POST 请求的 body

    const postData = JSON.parse(request.postData() || '{}');

    postData.mode = 'test';  // 添加测试标记

    await route.continue({

      postData: JSON.stringify(postData),

    });

  });

});

route.fetch() 真实请求

在 Mock 处理函数中,可以用 route.fetch() 实际发送请求并获取真实响应,然后修改。

实例

javascript

test('修改真实响应', async ({ page }) => {

  await page.route('**/api/products', async route => {

    // 先获取真实响应

    const response = await route.fetch();

    const body = await response.json();

    // 修改响应数据

    body.items[0].name = 'RUNOOB 修改后的商品名';

    // 返回修改后的数据

    await route.fulfill({

      status: response.status(),

      contentType: 'application/json',

      json: body,

    });

  });

});

Context 级拦截 vs Page 级拦截

方式作用范围适用场景
page.route()仅当前页面单个页面的网络 Mock
context.route()该 Context 下所有页面多个页面共享的 Mock 规则

实例

javascript

test.beforeEach(async ({ context }) => {

  // 在整个 Context 中拦截,所有页面生效

  await context.route('**/*.css', route => route.abort());

});

test('测试 1', async ({ page }) => { /* 无 CSS */ });

test('测试 2', async ({ page }) => { /* 无 CSS */ });

HAR 文件录制与回放

HAR(HTTP Archive)文件可以记录页面的所有网络请求,然后回放模拟。

实例

javascript

test('使用 HAR 文件 Mock', async ({ page }) => {

  // 从 HAR 文件加载网络记录并回放

  await page.routeFromHAR('tests/hars/api-responses.har');

  await page.goto('https://www.runoob.com/');

  // 所有匹配的请求将从 HAR 文件中获取响应

});
bash
# 录制 HAR 文件
npx playwright open --save-har=tests/hars/api-responses.har https://www.runoob.com/

HAR 文件适合 Mock 大量或复杂的 API 响应。先录制一次,之后测试都从 HAR 回放,不依赖真实服务器。

AI 思考中...

Playwright Codegen 测试生成器

Playwright 网络监控与 API 测试

基于 VitePress 构建,部署于 GitHub Pages