Skip to main content

模擬 API

簡介

Web APIs 通常實作為 HTTP 端點。Playwright 提供 mock修改 網路流量的 API,包括 HTTP 和 HTTPS。頁面所做的任何請求,包括 XHRsfetch 請求,都可以被追蹤、修改和 mock。使用 Playwright,你也可以使用包含頁面所做多個網路請求的 HAR 檔案來 mock。

模擬 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 mocking trace

了解更多關於進階網路

修改 API 回應

有時候,進行 API 請求是必要的,但需要修補回應以允許可重現的測試。在這種情況下,與其模擬請求,不如執行請求並用修改後的回應來完成它。

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

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

了解更多關於進階網路

使用 HAR 檔案進行模擬

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

  1. 記錄一個 HAR 檔案。
  2. 將 HAR 檔案與測試一起提交。
  3. 在測試中使用保存的 HAR 檔案來路由請求。

錄製 HAR 檔案

要記錄 HAR 檔案,我們使用 Page.RouteFromHARAsync()BrowserContext.RouteFromHARAsync() 方法。此方法需要 HAR 檔案的路徑和一個可選的選項物件。選項物件可以包含 URL,以便只有符合指定 glob 模式的 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 選項。這將會針對 HAR 檔案執行測試,而不是直接調用 API。

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

了解更多關於進階網路