Перехват сетевых запросов в Playwright

Перехват сетевых запросов в Playwright — очень полезная возможность в сценариях автоматизированного тестирования и веб-скрапинга, позволяющая перехватывать, изменять и имитировать сетевые запросы и ответы.

Playwright предоставляетpage.route()иpage.on('request') / page.on('response')и другие API, которые могут:

  • Перехват запросов: решать, разрешать ли, изменять URL/заголовки/тело или сразу возвращать мок-ответы.
  • Мониторинг запросов/ответов: просмотр URL запроса, метода, заголовков, кода состояния ответа, тела ответа и т. д.
  • Имитация сетевых ошибок: блокировать запросы, возвращать коды ошибок, тестировать логику отказоустойчивости приложения.

Типичные случаи использования:

  • Мок API: запускать UI-тесты фронтенда без API бэкенда.
  • Изменение запросов: например, добавить токен, протестировать некорректные заголовки.
  • Отладка производительности: подсчёт запросов, времени ответа.
  • Инъекция ошибок: имитировать серверные ошибки, такие как 500/404.

Перехват запросов:page.route()

await page.route('**/api/todos', async route => {
  // 拦截匹配的请求
  console.log('拦截到请求:', route.request().url());

  // 1. 直接放行(继续请求)
  await route.continue();

  // 2. 修改请求
  // await route.continue({ headers: { ...route.request().headers(), 'X-Test': 'true' } });

  // 3. 返回 mock 响应
  // await route.fulfill({
  //   status: 200,
  //   contentType: 'application/json',
  //   body: JSON.stringify([{ id: 1, text: 'mock todo', done: false }]),
  // });

  // 4. 拒绝请求
  // await route.abort();
});

Описание параметра:

  • page.route(url, handler): зарегистрировать перехватчик,urlподдерживает строку, регулярное выражение или**подстановочный знак.
  • route.request(): получить объект запроса.
  • route.continue([options]): разрешить запрос, можно изменить method, headers, postData.
  • route.fulfill(response): напрямую вернуть поддельный ответ.
  • route.abort([errorCode]): прервать запрос, распространённые коды ошибок, такие как"failed", "aborted", "timedout"。

Мониторинг запросов и ответов

// 监听所有请求
page.on('request', req => {
  console.log(`➡️ 请求: ${req.method()} ${req.url()}`);
});

// 监听所有响应
page.on('response', async res => {
  console.log(`⬅️ 响应: ${res.status()} ${res.url()}`);
});

// 获取响应 body
const response = await page.waitForResponse('**/api/data');
console.log('响应内容:', await response.text());

Часто используемые методы:

  • request.url() / request.method() / request.headers() / request.postData()
  • response.status() / response.headers() / response.text() / response.json()

Симуляция сетевой среды

Примеры

// Симуляция сетевой ошибки
await page.route('**/*.png', route => route.abort('failed'));

// Симуляция задержки
await page.route('**/api/**', async route => {
  await new Promise(r => setTimeout(r, 2000));
  await route.continue();
});
</pre>
<hr>
<h2>Полный пример: имитация API</h2>
import { test, expect } from '@playwright/test';

test('Перехват и имитация API', async ({ page }) => {
  // Перехватить запрос /api/todos и вернуть фиксированные данные
  await page.route('**/api/todos', async route => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify([
        { id: 1, text: 'Изучение Playwright', done: false },
        { id: 2, text: 'Написать автоматизированные тесты', done: истина },
      ]),
    });
  });

  await page.goto('https://example-todo-app.com');
  const items = await page.locator('.todo-item').allTextContents();
  console.log('Загруженные задачи:', items);

  // Проверка, что UI отображает mock-данные
  await expect(page.locator('.todo-item')).toHaveCount(2);
  await expect(page.locator('.todo-item').first()).toContainText('Playwright Learning');
});

API, связанные с перехватом сетевых запросов

API Назначение Общие параметры/описание
page.route(url, handler) Зарегистрировать перехват запроса urlМожет быть строкой/регулярным выражением/шаблоном с подстановочными знаками
route.request() Получить объект запроса ВозвращаетRequest
route.continue([options]) Разрешить запрос, можно изменить { method, headers, postData }
route.fulfill(response) Вернуть пользовательский ответ { status, headers, body, contentType }
route.abort([errorCode]) Прервать запрос Общие:'failed', 'aborted', 'timedout'
page.unroute(url, handler?) Удалить правило перехвата
page.on('request', cb) Мониторинг запроса
page.on('response', cb) Мониторинг ответа
request.url()/method()/headers()/postData() Информация о запросе
response.status()/headers()/text()/json() Информация об ответе
page.waitForResponse(urlOrPredicate) Ожидать конкретный ответ Можно передать URL или функцию
Другие расширения