ネットワーク
はじめに
Playwrightは、HTTPとHTTPSの両方で、ブラウザのネットワークトラフィックを監視および変更するためのAPIを提供します。XHRおよびfetchリクエストを含む、ページが行うあらゆるリクエストを追跡、変更、処理できます。
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'
}
});
});
Glob URLパターン
Playwrightは、page.route()やpage.waitForResponse()などのネットワークインターセプトメソッドでURLを照合するために、簡略化されたglobパターンを使用します。これらのパターンは基本的なワイルドカードをサポートしています。
- アスタリスク
- 単一の
*は/以外の任意の文字に一致します。 - 二重の
**は/を含む任意の文字に一致します。
- 単一の
- 疑問符
?は疑問符?のみに一致します。任意の文字に一致させたい場合は、代わりに*を使用してください。 - 中括弧
{}は、コンマ,で区切られたオプションのリストに一致させるために使用できます。 - バックスラッシュ
\は、特殊文字をエスケープするために使用できます(バックスラッシュ自体を\\としてエスケープすることに注意してください)。
例
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}はすべての画像リクエストに一致します。
重要な注意点
- globパターンは、URLの一部だけでなく、URL全体に一致する必要があります。
- URLマッチングにglobを使用する場合は、プロトコルやパスセパレータを含む完全なURL構造を考慮してください。
- より複雑なマッチング要件には、globパターンの代わりに正規表現を使用することを検討してください。
WebSockets
Playwrightは、WebSocketsの検査、モック、変更をすぐにサポートしています。APIモックガイドを参照して、WebSocketsをモックする方法を学習してください。
WebSocketが作成されるたびに、page.on('websocket')イベントが発火します。このイベントには、さらなるWebSocketフレーム検査のための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()の使用を検討してください。
- テストやネットワークモックにサービスワーカーのみを使用するのではなく、サービスワーカー自体が行ったリクエストのルーティングとリッスンに興味がある場合は、この実験的な機能を参照してください。