模拟 API
介绍
¥Introduction
Web API 通常作为 HTTP 端点来实现。Playwright 提供 API 来模拟和修改网络流量(HTTP 和 HTTPS)。页面所做的任何请求,包括 XHR 和 fetch 请求,都可以被跟踪、修改和模拟。通过 Playwright,你还可以使用包含页面触发的多个网络请求的 HAR 文件进行模拟。
¥Web APIs are usually implemented as HTTP endpoints. Playwright provides APIs to mock and modify network traffic, both HTTP and HTTPS. Any requests that a page does, including XHRs and fetch requests, can be tracked, modified and mocked. With Playwright you can also mock using HAR files that contain multiple network requests made by the page.
模拟 API 请求
¥Mock API requests
以下代码将拦截对 */**/api/v1/fruits
的所有调用,并返回自定义响应。不会向 API 触发任何请求。测试转到使用模拟路由的 URL,并断言页面上存在模拟数据。
¥The following code will intercept all the calls to */**/api/v1/fruits
and will return a custom response instead. No requests to the API will be made. The test goes to the URL that uses the mocked route and asserts that mock data is present on the page.
test("mocks a fruit and doesn't call api", async ({ page }) => {
// Mock the api call before navigating
await page.route('*/**/api/v1/fruits', async route => {
const json = [{ name: 'Strawberry', id: 21 }];
await route.fulfill({ json });
});
// Go to the page
await page.goto('https://demo.playwright.dev/api-mocking');
// Assert that the Strawberry fruit is visible
await expect(page.getByText('Strawberry')).toBeVisible();
});
从示例测试的跟踪中可以看到,该 API 从未被调用,而是通过模拟数据实现的。
¥You can see from the trace of the example test that the API was never called, it was however fulfilled with the mock data.
了解有关 高级网络 的更多信息。
¥Read more about advanced networking.
修改 API 响应
¥Modify API responses
有时,触发 API 请求是必要的,但需要对响应进行修补以允许进行可重复的测试。在这种情况下,我们可以执行请求并使用修改后的响应来满足请求,而不是模拟请求。
¥Sometimes, it is essential to make an API request, but the response needs to be patched to allow for reproducible testing. In that case, instead of mocking the request, one can perform the request and fulfill it with the modified response.
在下面的示例中,我们拦截对水果 API 的调用并向数据添加一个名为 'Loquat' 的新水果。然后我们转到该 url 并断言该数据存在:
¥In the example below we intercept the call to the fruit API and add a new fruit called 'Loquat', to the data. We then go to the url and assert that this data is there:
test('gets the json from api and adds a new fruit', async ({ page }) => {
// Get the response and add to it
await page.route('*/**/api/v1/fruits', async route => {
const response = await route.fetch();
const json = await response.json();
json.push({ name: 'Loquat', id: 100 });
// Fulfill using the original response, while patching the response body
// with the given JSON object.
await route.fulfill({ response, json });
});
// Go to the page
await page.goto('https://demo.playwright.dev/api-mocking');
// Assert that the new fruit is visible
await expect(page.getByText('Loquat', { exact: true })).toBeVisible();
});
在我们的测试跟踪中,我们可以看到 API 被调用并且响应被修改。
¥In the trace of our test we can see that the API was called and the response was modified.
通过检查响应,我们可以看到我们的新水果已添加到列表中。
¥By inspecting the response we can see that our new fruit was added to the list.
了解有关 高级网络 的更多信息。
¥Read more about advanced networking.
使用 HAR 文件进行模拟
¥Mocking with HAR files
HAR 文件是一个 HTTP 存档 文件,其中包含加载页面时触发的所有网络请求的记录。它包含有关请求和响应标头、cookie、内容、计时等的信息。你可以在测试中使用 HAR 文件来模拟网络请求。你需要:
¥A HAR file is an HTTP Archive file that contains a record of all the network requests that are made when a page is loaded. It contains information about the request and response headers, cookies, content, timings, and more. You can use HAR files to mock network requests in your tests. You'll need to:
-
录制 HAR 文件。
¥Record a HAR file.
-
与测试一起提交 HAR 文件。
¥Commit the HAR file alongside the tests.
-
使用测试中保存的 HAR 文件路由请求。
¥Route requests using the saved HAR files in the tests.
录制 HAR 文件
¥Recording a HAR file
为了记录 HAR 文件,我们使用 page.routeFromHAR() 或 browserContext.routeFromHAR() 方法。此方法接受 HAR 文件的路径和选项的可选对象。选项对象可以包含 URL,以便只有 URL 与指定的 glob 模式匹配的请求才会从 HAR 文件提供服务。如果未指定,所有请求都将从 HAR 文件提供服务。
¥To record a HAR file we use page.routeFromHAR() or browserContext.routeFromHAR() method. This method takes in the path to the HAR file and an optional object of options. The options object can contain the URL so that only requests with the URL matching the specified glob pattern will be served from the HAR File. If not specified, all requests will be served from the HAR file.
将 update
选项设置为 true 将使用实际网络信息创建或更新 HAR 文件,而不是处理来自 HAR 文件的请求。创建测试以使用真实数据填充 HAR 时使用它。
¥Setting update
option to true will create or update the HAR file with the actual network information instead of serving the requests from the HAR file. Use it when creating a test to populate the HAR with real data.
test('records or updates the HAR file', async ({ page }) => {
// Get the response from the HAR file
await page.routeFromHAR('./hars/fruit.har', {
url: '*/**/api/v1/fruits',
update: true,
});
// Go to the page
await page.goto('https://demo.playwright.dev/api-mocking');
// Assert that the fruit is visible
await expect(page.getByText('Strawberry')).toBeVisible();
});
修改 HAR 文件
¥Modifying a HAR file
录制 HAR 文件后,你可以通过打开 'hars' 文件夹内的散列 .txt 文件并编辑 JSON 来修改它。该文件应提交给你的源代码管理。每当你使用 update: true
运行此测试时,它都会根据 API 的请求更新你的 HAR 文件。
¥Once you have recorded a HAR file you can modify it by opening the hashed .txt file inside your 'hars' folder and editing the JSON. This file should be committed to your source control. Anytime you run this test with update: true
it will update your HAR file with the request from the API.
[
{
"name": "Playwright",
"id": 100
},
// ... other fruits
]
从 HAR 重播
¥Replaying from HAR
现在你已经记录了 HAR 文件并修改了模拟数据,它可以用于在测试中提供匹配的响应。为此,只需关闭或删除 update
选项即可。这将针对 HAR 文件运行测试,而不是访问 API。
¥Now that you have the HAR file recorded and modified the mock data, it can be used to serve matching responses in the test. For this, just turn off or simply remove the update
option. This will run the test against the HAR file instead of hitting the API.
test('gets the json from HAR and checks the new fruit has been added', async ({ page }) => {
// Replay API requests from HAR.
// Either use a matching response from the HAR,
// or abort the request if nothing matches.
await page.routeFromHAR('./hars/fruit.har', {
url: '*/**/api/v1/fruits',
update: false,
});
// Go to the page
await page.goto('https://demo.playwright.dev/api-mocking');
// Assert that the Playwright fruit is visible
await expect(page.getByText('Playwright', { exact: true })).toBeVisible();
});
在我们的测试跟踪中,我们可以看到路由是从 HAR 文件中完成的,并且没有调用 API。
¥In the trace of our test we can see that the route was fulfilled from the HAR file and the API was not called.
如果我们检查响应,我们可以看到我们的新水果已添加到 JSON,这是通过手动更新 hars
文件夹内的哈希 .txt
文件来完成的。
¥If we inspect the response we can see our new fruit was added to the JSON, which was done by manually updating the hashed .txt
file inside the hars
folder.
HAR 重放严格匹配 URL 和 HTTP 方法。对于 POST 请求,它还严格匹配 POST 负载。如果多个录音与一个请求匹配,则会选择具有最匹配标头的录音。将自动跟踪导致重定向的条目。
¥HAR replay matches URL and HTTP method strictly. For POST requests, it also matches POST payloads strictly. If multiple recordings match a request, the one with the most matching headers is picked. An entry resulting in a redirect will be followed automatically.
与录制时类似,如果给定的 HAR 文件名以 .zip
结尾,则将其视为包含 HAR 文件以及作为单独条目存储的网络有效负载的存档。你还可以提取此存档,手动编辑有效负载或 HAR 日志并指向提取的 har 文件。所有有效负载将相对于文件系统上提取的 har 文件进行解析。
¥Similar to when recording, if given HAR file name ends with .zip
, it is considered an archive containing the HAR file along with network payloads stored as separate entries. You can also extract this archive, edit payloads or HAR log manually and point to the extracted har file. All the payloads will be resolved relative to the extracted har file on the file system.
使用 CLI 记录 HAR
¥Recording HAR with CLI
我们建议你使用 update
选项来记录 HAR 文件以进行测试。但是,你也可以使用 Playwright CLI 录制 HAR。
¥We recommend the update
option to record HAR file for your test. However, you can also record the HAR with Playwright CLI.
使用 Playwright CLI 打开浏览器并传递 --save-har
选项以生成 HAR 文件。或者,使用 --save-har-glob
仅保存你感兴趣的请求,例如 API 端点。如果 har 文件名以 .zip
结尾,则工件将作为单独的文件写入,并全部压缩到单个 zip
中。
¥Open the browser with Playwright CLI and pass --save-har
option to produce a HAR file. Optionally, use --save-har-glob
to only save requests you are interested in, for example API endpoints. If the har file name ends with .zip
, artifacts are written as separate files and are all compressed into a single zip
.
# Save API requests from example.com as "example.har" archive.
npx playwright open --save-har=example.har --save-har-glob="**/api/**" https://example.com
了解有关 高级网络 的更多信息。
¥Read more about advanced networking.
模拟 WebSockets
¥Mock WebSockets
以下代码将拦截 WebSocket 连接并模拟通过 WebSocket 进行的整个通信,而不是连接到服务器。此示例使用 "response"
响应 "request"
。
¥The following code will intercept WebSocket connections and mock entire communcation over the WebSocket, instead of connecting to the server. This example responds to a "request"
with a "response"
.
await page.routeWebSocket('wss://example.com/ws', ws => {
ws.onMessage(message => {
if (message === 'request')
ws.send('response');
});
});
或者,你可能希望连接到实际的服务器,但拦截中间的消息并修改或阻止它们。以下是修改页面发送到服务器的一些消息的示例,其余消息保持不变。
¥Alternatively, you may want to connect to the actual server, but intercept messages in-between and modify or block them. Here is an example that modifies some of the messages sent by the page to the server, and leaves the rest unmodified.
await page.routeWebSocket('wss://example.com/ws', ws => {
const server = ws.connectToServer();
ws.onMessage(message => {
if (message === 'request')
server.send('request2');
else
server.send(message);
});
});
有关更多详细信息,请参阅 WebSocketRoute。
¥For more details, see WebSocketRoute.