メインコンテンツへスキップ

モックAPI

はじめに

Web APIは通常、HTTPエンドポイントとして実装されています。Playwrightは、HTTPとHTTPSの両方のネットワークトラフィックを**モック**および**変更**するためのAPIを提供します。ページが行うすべてのリクエスト(XHRおよびfetchリクエストを含む)を追跡、変更、モックすることができます。Playwrightを使用すると、ページが行った複数のネットワークリクエストを含むHARファイルを使用してモックすることもできます。

APIリクエストのモック

以下のコードは、*/**/api/v1/fruitsへのすべての呼び出しを傍受し、代わりにカスタムレスポンスを返します。APIへのリクエストは行われません。テストはモックされたルートを使用するURLに移動し、モックデータがページに存在することを確認します。

test("mocks a fruit and doesn't call api", async ({ page }) => {
// Mock the api call before navigating
await page.route('*/**/api/v1/fruits', async route => {
const json = [{ name: 'Strawberry', id: 21 }];
await route.fulfill({ json });
});
// Go to the page
await page.goto('https://demo.playwright.dev/api-mocking');

// Assert that the Strawberry fruit is visible
await expect(page.getByText('Strawberry')).toBeVisible();
});

例のテストのトレースから、APIが呼び出されず、モックデータで応答されたことがわかります。api mocking trace

高度なネットワークについて詳しく読む。

APIレスポンスの変更

APIリクエストを行うことが不可欠な場合がありますが、再現性のあるテストを可能にするためにレスポンスをパッチ適用する必要がある場合があります。その場合、リクエストをモックするのではなく、リクエストを実行し、変更されたレスポンスで応答することができます。

以下の例では、果物APIへの呼び出しを傍受し、「Loquat」という新しい果物をデータに追加します。次にURLに移動し、このデータが存在することを確認します。

test('gets the json from api and adds a new fruit', async ({ page }) => {
// Get the response and add to it
await page.route('*/**/api/v1/fruits', async route => {
const response = await route.fetch();
const json = await response.json();
json.push({ name: 'Loquat', id: 100 });
// Fulfill using the original response, while patching the response body
// with the given JSON object.
await route.fulfill({ response, json });
});

// Go to the page
await page.goto('https://demo.playwright.dev/api-mocking');

// Assert that the new fruit is visible
await expect(page.getByText('Loquat', { exact: true })).toBeVisible();
});

テストのトレースでは、APIが呼び出され、レスポンスが変更されたことがわかります。trace of test showing api being called and fulfilled

レスポンスを検査すると、新しい果物がリストに追加されていることがわかります。trace of test showing the mock response

高度なネットワークについて詳しく読む。

HARファイルによるモック

HARファイルは、ページがロードされたときに行われたすべてのネットワークリクエストの記録を含むHTTP Archiveファイルです。リクエストとレスポンスのヘッダー、クッキー、コンテンツ、タイミングなどの情報が含まれています。HARファイルを使用して、テストでネットワークリクエストをモックすることができます。次の手順が必要です。

  1. HARファイルを記録します。
  2. テストとともにHARファイルをコミットします。
  3. 保存されたHARファイルを使用してテストでリクエストをルーティングします。

HARファイルの記録

HARファイルを記録するには、page.routeFromHAR()またはbrowserContext.routeFromHAR()メソッドを使用します。このメソッドは、HARファイルへのパスとオプションのオブジェクトを受け取ります。オプションオブジェクトにはURLを含めることができ、指定されたグロブパターンに一致するURLを持つリクエストのみがHARファイルから提供されます。指定しない場合、すべてのリクエストはHARファイルから提供されます。

updateオプションをtrueに設定すると、HARファイルからリクエストを提供する代わりに、実際のネットワーク情報でHARファイルが作成または更新されます。テスト作成時にHARに実際のデータを投入するためにこれを使用します。

test('records or updates the HAR file', async ({ page }) => {
// Get the response from the HAR file
await page.routeFromHAR('./hars/fruit.har', {
url: '*/**/api/v1/fruits',
update: true,
});

// Go to the page
await page.goto('https://demo.playwright.dev/api-mocking');

// Assert that the fruit is visible
await expect(page.getByText('Strawberry')).toBeVisible();
});

HARファイルの変更

HARファイルを記録したら、「hars」フォルダ内のハッシュ化された.txtファイルを開き、JSONを編集することで変更できます。このファイルはソース管理にコミットする必要があります。update: trueでこのテストを実行するたびに、APIからのリクエストでHARファイルが更新されます。

[
{
"name": "Playwright",
"id": 100
},
// ... other fruits
]

HARからのリプレイ

HARファイルが記録され、モックデータが変更されたので、テストで一致するレスポンスを提供するために使用できます。このためには、updateオプションをオフにするか、単に削除するだけです。これにより、APIを呼び出す代わりにHARファイルに対してテストが実行されます。

test('gets the json from HAR and checks the new fruit has been added', async ({ page }) => {
// Replay API requests from HAR.
// Either use a matching response from the HAR,
// or abort the request if nothing matches.
await page.routeFromHAR('./hars/fruit.har', {
url: '*/**/api/v1/fruits',
update: false,
});

// Go to the page
await page.goto('https://demo.playwright.dev/api-mocking');

// Assert that the Playwright fruit is visible
await expect(page.getByText('Playwright', { exact: true })).toBeVisible();
});

テストのトレースでは、HARファイルからルートが応答され、APIが呼び出されなかったことがわかります。trace showing the HAR file being used

レスポンスを検査すると、「hars」フォルダ内のハッシュ化された.txtファイルを手動で更新することで、新しい果物がJSONに追加されたことがわかります。trace showing response from HAR file

HARのリプレイは、URLとHTTPメソッドに厳密に一致します。POSTリクエストの場合、POSTペイロードにも厳密に一致します。複数の記録がリクエストに一致する場合、最も一致するヘッダーを持つものが選択されます。リダイレクトを生成するエントリは自動的に追跡されます。

記録時と同様に、与えられたHARファイル名が.zipで終わる場合、それはHARファイルと別々のエントリとして保存されたネットワークペイロードを含むアーカイブと見なされます。このアーカイブを解凍し、ペイロードやHARログを手動で編集し、解凍されたHARファイルを指定することもできます。すべてのペイロードは、ファイルシステム上の解凍されたHARファイルに対して相対的に解決されます。

CLIでのHAR記録

テストのHARファイルを記録するには、updateオプションをお勧めします。ただし、Playwright CLIでHARを記録することもできます。

Playwright CLIでブラウザを開き、--save-harオプションを渡してHARファイルを生成します。必要に応じて、--save-har-globを使用して、APIエンドポイントなど、関心のあるリクエストのみを保存します。HARファイル名が.zipで終わる場合、アーティファクトは別々のファイルとして書き込まれ、すべて単一のzipに圧縮されます。

# Save API requests from example.com as "example.har" archive.
npx playwright open --save-har=example.har --save-har-glob="**/api/**" https://example.com

高度なネットワークについて詳しく読む。

WebSocketのモック

以下のコードはWebSocket接続を傍受し、サーバーに接続する代わりにWebSocket経由の通信全体をモックします。この例では、"request"に対して"response"で応答します。

await page.routeWebSocket('wss://example.com/ws', ws => {
ws.onMessage(message => {
if (message === 'request')
ws.send('response');
});
});

あるいは、実際のサーバーに接続しつつ、途中のメッセージを傍受して変更またはブロックすることもできます。以下は、ページからサーバーに送信される一部のメッセージを変更し、残りを変更しないままにする例です。

await page.routeWebSocket('wss://example.com/ws', ws => {
const server = ws.connectToServer();
ws.onMessage(message => {
if (message === 'request')
server.send('request2');
else
server.send(message);
});
});

詳細については、WebSocketRouteを参照してください。