模擬 API
簡介
Web APIs 通常實作為 HTTP 端點。Playwright 提供 mock 和 修改 網路流量的 API,包括 HTTP 和 HTTPS。頁面所做的任何請求,包括 XHRs 和 fetch 請求,都可以被追蹤、修改和 mock。使用 Playwright,你也可以使用包含頁面所做多個網路請求的 HAR 檔案來 mock。
模擬 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 的呼叫並新增一個名為 'Loquat' 的水果到資料中。然後我們訪問該 url 並確認這些資料存在:
page.route("*/**/api/v1/fruits", route -> {
Response response = route.fetch();
byte[] json = response.body();
parsed = new Gson().fromJson(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(json.toString()));
});
// Go to the page
page.goto("https://demo.playwright.dev/api-mocking");
// Assert that the Loquat fruit is visible
assertThat(page.getByText("Loquat", new Page.GetByTextOptions().setExact(true))).isVisible();
在我們測試的追蹤中,我們可以看到 API 被呼叫且回應被修改。
透過檢查回應,我們可以看到我們的新水果已被添加到列表中。
了解更多關於進階網路。
使用 HAR 檔案進行模擬
A HAR 檔案是個 HTTP Archive 檔案,包含頁面載入時所有網路請求的記錄。它包含有關請求和回應標頭、cookies、內容、時間等的資訊。你可以使用 HAR 檔案在測試中模擬網路請求。你需要:
- 記錄一個 HAR 檔案。
- 將 HAR 檔案與測試一起提交。
- 在測試中使用保存的 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.goto("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.goto("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 沒有被呼叫。
如果我們檢查回應,我們可以看到我們的新水果已經添加到 JSON 中,這是通過手動更新 hars
資料夾內的雜湊 .txt
文件完成的。
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"
了解更多關於進階網路。