跳到主要內容

模擬 API

簡介

Web API 通常以 HTTP 端點實作。Playwright 提供 API 來模擬修改網路流量,包括 HTTP 和 HTTPS。頁面執行的任何請求,包含 XHRfetch 請求,都可以被追蹤、修改和模擬。透過 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 mocking trace

閱讀更多關於進階網路功能的資訊。

修改 API 回應

有時,必須發出 API 請求,但需要修補回應以實現可重現的測試。在這種情況下,可以執行請求並使用修改後的回應來完成請求,而不是模擬請求。

在下面的範例中,我們攔截對水果 API 的呼叫,並將一個名為 'Loquat' 的新水果新增到資料中。然後我們前往 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 被呼叫,並且回應被修改。 trace of test showing api being called and fulfilled

透過檢查回應,我們可以看見我們的新水果已新增到列表中。 trace of test showing the mock response

閱讀更多關於進階網路功能的資訊。

使用 HAR 檔案進行模擬

HAR 檔案是一個 HTTP Archive 檔案,其中包含頁面載入時發出的所有網路請求的記錄。它包含有關請求和回應標頭、Cookie、內容、時間等的資訊。您可以使用 HAR 檔案來模擬測試中的網路請求。您需要

  1. 錄製 HAR 檔案。
  2. 將 HAR 檔案與測試一起提交。
  3. 在測試中使用已儲存的 HAR 檔案路由請求。

錄製 HAR 檔案

為了錄製 HAR 檔案,我們使用 Page.routeFromHAR()BrowserContext.routeFromHAR() 方法。此方法接受 HAR 檔案的路徑和一個可選的選項物件。選項物件可以包含 URL,以便只有與指定 glob 模式匹配的 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 選項。這將針對 HAR 檔案執行測試,而不是訪問 API。

// 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 沒有被呼叫。 trace showing the HAR file being used

如果我們檢查回應,我們可以看到我們的新水果已新增到 JSON 中,這是透過手動更新 hars 資料夾內的雜湊 .txt 檔案完成的。 trace showing response from HAR file

HAR 重播嚴格匹配 URL 和 HTTP 方法。對於 POST 請求,它也嚴格匹配 POST 負載。如果多個錄製匹配一個請求,則會選擇具有最多匹配標頭的那個。導致重定向的條目將會自動跟隨。

與錄製時類似,如果給定的 HAR 檔案名稱以 .zip 結尾,則它被視為一個封存檔,其中包含 HAR 檔案以及儲存為單獨條目的網路負載。您也可以解壓縮此封存檔,手動編輯負載或 HAR 日誌,並指向解壓縮的 har 檔案。所有負載都將相對於檔案系統上解壓縮的 har 檔案進行解析。

使用 CLI 錄製 HAR 檔案

我們建議使用 update 選項來為您的測試錄製 HAR 檔案。但是,您也可以使用 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 上的通訊,而不是連線到伺服器。此範例使用 "response" 回應 "request"

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