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

モックAPI

はじめに

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

APIリクエストのモック

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

// Intercept the route to the fruit API
await page.RouteAsync("*/**/api/v1/fruits", async route => {
var json = new[] { new { name = "Strawberry", id = 21 } };
// fulfill the route with the mock data
await route.FulfillAsync(new()
{
Json = json
});
});

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

// Assert that the Strawberry fruit is visible
await Expect(page.GetByTextAsync("Strawberry")).ToBeVisibleAsync();

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

高度なネットワークについて詳しくはこちらをご覧ください。

APIレスポンスの変更

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

以下の例では、フルーツAPIへの呼び出しをインターセプトし、データに「ビワ」という新しいフルーツを追加します。その後、URLに移動し、このデータが存在することを確認します。

await page.RouteAsync("*/**/api/v1/fruits", async (route) => {
var response = await route.FetchAsync();
var fruits = await response.JsonAsync<Fruit[]>();
fruits.Add(new Fruit() { Name = "Loquat", Id = 100 });
// Fulfill using the original response, while patching the response body
// with the given JSON object.
await route.FulfillAsync(new ()
{
Response = response,
Json = fruits
});
}
);
// Go to the page
await page.GotoAsync("https://demo.playwright.dev/api-mocking");

// Assert that the Loquat fruit is visible
await Expect(page.GetByTextAsync("Loquat", new () { Exact = true })).ToBeVisibleAsync();

テストのトレースでは、APIが呼び出され、レスポンスが変更されたことがわかります。 APIが呼び出され、応答されたことを示すテストのトレkース

レスポンスを検査すると、新しいフルーツがリストに追加されたことがわかります。 モックレスポンスを示すテストのトレース

高度なネットワークについて詳しくはこちらをご覧ください。

HARファイルを使用したモック

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

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

HARファイルの記録

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

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

// Get the response from the HAR file
await page.RouteFromHARAsync("./hars/fruit.har", new () {
Url = "*/**/api/v1/fruits",
Update = true,
});

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

// Assert that the fruit is visible
await Expect(page.GetByText("Strawberry")).ToBeVisibleAsync();

HARファイルの変更

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

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

HARからのリプレイ

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

// Replay API requests from HAR.
// Either use a matching response from the HAR,
// or abort the request if nothing matches.
await page.RouteFromHARAsync("./hars/fruit.har", new ()
{
Url = "*/**/api/v1/fruits",
Update = false,
}
);

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

// Assert that the Playwright fruit is visible
await page.ExpectByTextAsync("Playwright", new() { Exact = true }).ToBeVisibleAsync();

テストのトレースでは、ルートがHARファイルから応答され、APIが呼び出されなかったことがわかります。 HARファイルが使用されたことを示すトレース

レスポンスを検査すると、新しいフルーツがJSONに追加されたことがわかります。これは、`hars`フォルダ内のハッシュ化された`.txt`ファイルを手動で更新することで行われました。 HARファイルからの応答を示すトレース

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.
pwsh bin/Debug/netX/playwright.ps1 open --save-har=example.har --save-har-glob="**/api/**" https://example.com

高度なネットワークについて詳しくはこちらをご覧ください。

WebSocketのモック

以下のコードは、WebSocket接続をインターセプトし、サーバーに接続する代わりにWebSocket上の通信全体をモックします。この例では、`"request"`に対して`"response"`で応答します。

await page.RouteWebSocketAsync("wss://example.com/ws", ws => {
ws.OnMessage(frame => {
if (frame.Text == "request")
ws.Send("response");
});
});

あるいは、実際のサーバーに接続しつつ、その途中でメッセージをインターセプトして変更したりブロックしたりしたい場合もあるでしょう。以下は、ページからサーバーに送信されたメッセージの一部を変更し、残りを未変更のままにする例です。

await page.RouteWebSocketAsync("wss://example.com/ws", ws => {
var server = ws.ConnectToServer();
ws.OnMessage(frame => {
if (frame.Text == "request")
server.Send("request2");
else
server.Send(frame.Text);
});
});

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