Playwright ネットワークインターセプト
Playwright のネットワークインターセプト (Network Interception) は、自動テストやスクレイピングのシナリオで非常に有用な機能であり、ネットワークリクエストとレスポンスをインターセプト、変更、シミュレートすることができます。
Playwright は以下の API を提供しています。page.route()とpage.on('request') / page.on('response')これらの API を使用すると、次のことができます:
- リクエストのインターセプト:通過させるかどうかを決定し、URL/headers/body を変更し、またはモックレスポンスを直接返します。
- リクエスト/レスポンスの監視:リクエストの URL、メソッド、ヘッダー、レスポンスステータスコード、レスポンスボディなどを確認します。
- ネットワークエラーのシミュレーション:リクエストをブロックし、エラーコードを返し、アプリのフォールトトレラントロジックをテストします。
よくある応用シナリオ:
- Mock API:バックエンド API がなくてもフロントエンド UI テストを実行できます。
- リクエストの変更:例えば、トークンを追加して異常なヘッダーをテストします。
- パフォーマンスのデバッグ:リクエスト数やレスポンス時間を集計します。
- エラー注入: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]):リクエストを通過させ、メソッド、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>完全な例:Mock API</h2>
import { test, expect } from '@playwright/test';
test('インターセプトして mock 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: true },
]),
});
});
await page.goto('https://example-todo-app.com');
const items = await page.locator('.todo-item').allTextContents();
console.log('読み込まれたToDo:', items);
// UI に mock データが表示されることを検証する
await expect(page.locator('.todo-item')).toHaveCount(2);
await expect(page.locator('.todo-item').first()).toContainText('Playwright 学習');
});
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>完全な例:Mock API</h2>
import { test, expect } from '@playwright/test';
test('インターセプトして mock 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: true },
]),
});
});
await page.goto('https://example-todo-app.com');
const items = await page.locator('.todo-item').allTextContents();
console.log('読み込まれたToDo:', items);
// UI に mock データが表示されることを検証する
await expect(page.locator('.todo-item')).toHaveCount(2);
await expect(page.locator('.todo-item').first()).toContainText('Playwright 学習');
});
ネットワークインターセプト関連の 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 または関数を渡すことが可能 |