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

モックAPI

はじめに

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

APIリクエストのモック

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

// Intercept the route to the fruit API
page.route("https://fruit.ceo/api/breeds/image/random", route -> {
List<Dictionary<String, Object>> data = new ArrayList<Dictionary<String, Object>>();
Hashtable<String, Object> dict = new Hashtable<String, Object>();
dict.put("name", "Strawberry");
dict.put("id", 21);
data.add(dict);
// fulfill the route with the mock data
route.fulfill(RequestOptions.create().setData(data));
});

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

// Assert that the Strawberry fruit is visible
assertThat(page.getByText("Strawberry")).isVisible();

テスト例のトレースからわかるように、APIは呼び出されていませんが、モックデータで応答が完了しています。 APIモックのトレース

詳細については、高度なネットワークを参照してください。

APIレスポンスの変更

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

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

page.route("*/**/api/v1/fruits", route -> {
Response response = route.fetch();
byte[] json = response.body();
JsonObject parsed = new Gson().fromJson(new String(json), JsonObject.class);
parsed.add(new JsonObject().add("name", "Loquat").add("id", 100));
// Fulfill using the original response, while patching the response body
// with the given JSON object.
route.fulfill(new Route.FulfillOptions().setResponse(response).setBody(parsed.toString()));
});

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

// Assert that the Loquat fruit is visible
assertThat(page.getByText("Loquat", new Page.GetByTextOptions().setExact(true))).isVisible();

テストのトレースで、APIが呼び出され、レスポンスが変更されたことを確認できます。 APIが呼び出され応答が完了したことを示すテストのトレ3ス

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

詳細については、高度なネットワークを参照してください。

HARファイルによるモック

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

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

HARファイルの記録

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

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

// Get the response from the HAR file
page.routeFromHAR(Path.of("./hars/fruit.har"), new RouteFromHAROptions()
.setUrl("*/**/api/v1/fruits")
.setUpdate(true)
);

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

// Assert that the fruit is visible
assertThat(page.getByText("Strawberry")).isVisible();

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.
page.routeFromHAR(Path.of("./hars/fruit.har"), new RouteFromHAROptions()
.setUrl("*/**/api/v1/fruits")
.setUpdate(false)
);

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

// Assert that the Playwright fruit is visible
assertThat(page.getByText("Playwright", new Page.GetByTextOptions()
.setExact(true))).isVisible();

テストのトレースで、ルートが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.
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="open --save-har=example.har --save-har-glob='**/api/**' https://example.com"

詳細については、高度なネットワークを参照してください。

WebSocketのモック

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

page.routeWebSocket("wss://example.com/ws", ws -> {
ws.onMessage(frame -> {
if ("request".equals(frame.text()))
ws.send("response");
});
});

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

page.routeWebSocket("wss://example.com/ws", ws -> {
WebSocketRoute server = ws.connectToServer();
ws.onMessage(frame -> {
if ("request".equals(frame.text()))
server.send("request2");
else
server.send(frame.text());
});
});

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