ネットワーク
はじめに
Playwrightは、HTTPとHTTPSの両方でブラウザのネットワークトラフィックを監視および変更するためのAPIを提供します。ページが行うすべてのリクエスト(XHRおよびフェッチリクエストを含む)を追跡、変更、および処理できます。
APIのモック
APIモックガイドをチェックして、以下の方法について詳しく学んでください。
- APIリクエストをモックし、APIにヒットさせない
- APIリクエストを実行し、レスポンスを変更する
- HARファイルを使用してネットワークリクエストをモックする。
ネットワークモック
ネットワークリクエストをモックするために何も設定する必要はありません。ブラウザコンテキストのネットワークをモックするカスタムのRouteを定義するだけです。
import { test, expect } from '@playwright/test';
test.beforeEach(async ({ context }) => {
// Block any css requests for each test in this file.
await context.route(/.css$/, route => route.abort());
});
test('loads page without css', async ({ page }) => {
await page.goto('https://playwright.dokyumento.jp');
// ... test goes here
});
あるいは、単一のページでネットワークをモックするにはpage.route()を使用できます。
import { test, expect } from '@playwright/test';
test('loads page without images', async ({ page }) => {
// Block png and jpeg images.
await page.route(/(png|jpeg)$/, route => route.abort());
await page.goto('https://playwright.dokyumento.jp');
// ... test goes here
});
HTTP認証
HTTP認証を実行します。
- テスト
- ライブラリ
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
httpCredentials: {
username: 'bill',
password: 'pa55w0rd',
}
}
});
const context = await browser.newContext({
httpCredentials: {
username: 'bill',
password: 'pa55w0rd',
},
});
const page = await context.newPage();
await page.goto('https://example.com');
HTTPプロキシ
HTTP(S)プロキシまたはSOCKSv5経由でページを読み込むように設定できます。プロキシはブラウザ全体にグローバルに設定することも、各ブラウザコンテキストに個別に設定することもできます。
必要に応じてHTTP(S)プロキシのユーザー名とパスワードを指定でき、プロキシをバイパスするホストも指定できます。
以下はグローバルプロキシの例です。
- テスト
- ライブラリ
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
proxy: {
server: 'http://myproxy.com:3128',
username: 'usr',
password: 'pwd'
}
}
});
const browser = await chromium.launch({
proxy: {
server: 'http://myproxy.com:3128',
username: 'usr',
password: 'pwd'
}
});
コンテキストごとに指定することも可能です。
- テスト
- ライブラリ
import { test, expect } from '@playwright/test';
test('should use custom proxy on a new context', async ({ browser }) => {
const context = await browser.newContext({
proxy: {
server: 'http://myproxy.com:3128',
}
});
const page = await context.newPage();
await context.close();
});
const browser = await chromium.launch();
const context = await browser.newContext({
proxy: { server: 'http://myproxy.com:3128' }
});
ネットワークイベント
// Subscribe to 'request' and 'response' events.
page.on('request', request => console.log('>>', request.method(), request.url()));
page.on('response', response => console.log('<<', response.status(), response.url()));
await page.goto('https://example.com');
または、ボタンクリック後にpage.waitForResponse()でネットワーク応答を待つことができます。
// Use a glob URL pattern. Note no await.
const responsePromise = page.waitForResponse('**/api/fetch_data');
await page.getByText('Update').click();
const response = await responsePromise;
バリエーション
page.waitForResponse()でレスポンスを待機します。
// Use a RegExp. Note no await.
const responsePromise = page.waitForResponse(/\.jpeg$/);
await page.getByText('Update').click();
const response = await responsePromise;
// Use a predicate taking a Response object. Note no await.
const responsePromise = page.waitForResponse(response => response.url().includes(token));
await page.getByText('Update').click();
const response = await responsePromise;
リクエストの処理
await page.route('**/api/fetch_data', route => route.fulfill({
status: 200,
body: testData,
}));
await page.goto('https://example.com');
Playwrightスクリプトでネットワークリクエストを処理することで、APIエンドポイントをモックできます。
バリエーション
ブラウザコンテキスト全体にbrowserContext.route()で、またはページにpage.route()でルートを設定します。これはポップアップウィンドウや開かれたリンクにも適用されます。
await browserContext.route('**/api/login', route => route.fulfill({
status: 200,
body: 'accept',
}));
await page.goto('https://example.com');
リクエストの変更
// Delete header
await page.route('**/*', async route => {
const headers = route.request().headers();
delete headers['X-Secret'];
await route.continue({ headers });
});
// Continue requests as POST.
await page.route('**/*', route => route.continue({ method: 'POST' }));
変更を加えてリクエストを続行できます。上記の例では、送信されるリクエストからHTTPヘッダーを削除しています。
リクエストの中止
page.route()とroute.abort()を使用してリクエストを中止できます。
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
// Abort based on the request type
await page.route('**/*', route => {
return route.request().resourceType() === 'image' ? route.abort() : route.continue();
});
レスポンスの変更
レスポンスを変更するには、APIRequestContextを使用して元のレスポンスを取得し、そのレスポンスをroute.fulfill()に渡します。オプションを使用してレスポンスの個々のフィールドをオーバーライドできます。
await page.route('**/title.html', async route => {
// Fetch original response.
const response = await route.fetch();
// Add a prefix to the title.
let body = await response.text();
body = body.replace('<title>', '<title>My prefix:');
await route.fulfill({
// Pass all fields from the response.
response,
// Override response body.
body,
// Force content type to be html.
headers: {
...response.headers(),
'content-type': 'text/html'
}
});
});
グロブURLパターン
Playwrightは、page.route()やpage.waitForResponse()のようなネットワークインターセプトメソッドでのURLマッチングに簡略化されたグロブパターンを使用します。これらのパターンは基本的なワイルドカードをサポートしています。
- アスタリスク
- 単一の
*
は/
を除く任意の文字にマッチします。 - 二重の
**
は/
を含む任意の文字にマッチします。
- 単一の
- 疑問符
?
は疑問符?
のみにマッチします。任意の文字にマッチさせたい場合は、代わりに*
を使用してください。 - 波括弧
{}
は、コンマ,
で区切られたオプションのリストにマッチするために使用できます。 - バックスラッシュ
\
は、任意の特殊文字をエスケープするために使用できます(バックスラッシュ自体をエスケープするには\\
を使用することに注意)。
例
https://example.com/*.js
はhttps://example.com/file.js
にマッチしますが、https://example.com/path/file.js
にはマッチしません。https://example.com/?page=1
はhttps://example.com/?page=1
にマッチしますが、https://example.com
にはマッチしません。**/*.js
はhttps://example.com/file.js
とhttps://example.com/path/file.js
の両方にマッチします。**/*.{png,jpg,jpeg}
はすべての画像リクエストにマッチします。
重要な注意事項
- グロブパターンは、URLの一部ではなく、URL全体にマッチする必要があります。
- URLマッチングにグロブを使用する場合、プロトコルやパス区切り文字を含む完全なURL構造を考慮してください。
- より複雑なマッチング要件の場合は、グロブパターンではなくRegExpの使用を検討してください。
WebSockets
PlaywrightはWebSocketsの検査、モック、変更をすぐにサポートしています。WebSocketsのモック方法については、APIモックガイドを参照してください。
WebSocketが作成されるたびに、page.on('websocket')イベントが発火します。このイベントには、その後のWebソケットフレームの検査のためのWebSocketインスタンスが含まれます。
page.on('websocket', ws => {
console.log(`WebSocket opened: ${ws.url()}>`);
ws.on('framesent', event => console.log(event.payload));
ws.on('framereceived', event => console.log(event.payload));
ws.on('close', () => console.log('WebSocket closed'));
});
不足しているネットワークイベントとサービスワーカー
Playwrightの組み込みのbrowserContext.route()およびpage.route()を使用すると、テストでネイティブにリクエストをルーティングし、モックとインターセプトを実行できます。
- PlaywrightのネイティブなbrowserContext.route()とpage.route()を使用しているにもかかわらず、ネットワークイベントが不足しているように見える場合は、serviceWorkersを
'block'
に設定してサービスワーカーを無効にしてください。 - Mock Service Worker (MSW)のようなモックツールを使用している可能性があります。このツールはレスポンスのモックにはそのまま動作しますが、ネットワークリクエストを引き継ぐ独自のサービスワーカーを追加するため、それらのリクエストがbrowserContext.route()およびpage.route()から見えなくなります。ネットワークテストとモックの両方に興味がある場合は、レスポンスモックに組み込みのbrowserContext.route()とpage.route()を使用することを検討してください。
- テストとネットワークモックのためにサービスワーカーを使用するだけでなく、サービスワーカー自身によって行われたリクエストをルーティングおよびリッスンすることに興味がある場合は、この実験的機能を参照してください。