Skip to main content

模擬 API

簡介​

Web API 通常以 HTTP 端點的方式實作。Playwright 提供 API 來模擬和修改網路流量,包含 HTTP 和 HTTPS。頁面發出的任何請求,包括 XHR 和 fetch 請求,都可以被追蹤、修改和模擬。您也可以使用包含頁面多個網路請求的 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,這樣只有符合指定萬用字元模式的 URL 請求才會從 HAR 檔案提供。如果未指定,所有請求都會從 HAR 檔案提供。

將 update 選項設為 true 會建立或更新 HAR 檔案,包含實際的網路資訊,而不是從 HAR 檔案提供請求。建立測試時使用此選項可以用真實資料填充 HAR。

或者,您也可以在建立瀏覽器情境時,於 Browser.newContext() 中使用 setRecordHarPath 選項來錄製 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。