Перейти к основному содержимому

Мокирование API

Введение

Веб-API обычно реализуются как HTTP-эндпоинты. Playwright предоставляет API для мокирования и модификации сетевого трафика, как HTTP, так и HTTPS. Любые запросы, которые делает страница, включая XHRs и fetch запросы, могут быть отслежены, изменены и замокированы. С помощью Playwright вы также можете мокировать, используя HAR-файлы, содержащие несколько сетевых запросов, сделанных страницей.

Мокирование API-запросов

Следующий код перехватит все вызовы к */**/api/v1/fruits и вернет пользовательский ответ вместо этого. Запросы к API не будут выполнены. Тест переходит на URL, который использует замокированный маршрут, и проверяет, что замокированные данные присутствуют на странице.

def test_mock_the_fruit_api(page: Page):
def handle(route: Route):
json = [{"name": "Strawberry", "id": 21}]
# fulfill the route with the mock data
route.fulfill(json=json)

# Intercept the route to the fruit API
page.route("*/**/api/v1/fruits", handle)

# Go to the page
page.goto("https://demo.playwright.dev/api-mocking")

# Assert that the Strawberry fruit is visible
expect(page.get_by_text("Strawberry")).to_be_visible()

Вы можете увидеть из трассировки теста, что API никогда не вызывался, однако он был выполнен с замокированными данными. api mocking trace

Подробнее о продвинутой работе с сетью.

Модификация ответов API

Иногда необходимо выполнить запрос к API, но ответ нужно изменить для обеспечения воспроизводимого тестирования. В этом случае, вместо мокирования запроса, можно выполнить запрос и выполнить его с измененным ответом.

В примере ниже мы перехватываем вызов к API фруктов и добавляем новый фрукт под названием 'Loquat' в данные. Затем мы переходим на URL и проверяем, что эти данные присутствуют:

def test_gets_the_json_from_api_and_adds_a_new_fruit(page: Page):
def handle(route: Route):
response = route.fetch()
json = response.json()
json.append({ "name": "Loquat", "id": 100})
# Fulfill using the original response, while patching the response body
# with the given JSON object.
route.fulfill(response=response, json=json)

page.route("https://demo.playwright.dev/api-mocking/api/v1/fruits", handle)

# Go to the page
page.goto("https://demo.playwright.dev/api-mocking")

# Assert that the new fruit is visible
expect(page.get_by_text("Loquat", exact=True)).to_be_visible()

В трассировке нашего теста мы можем увидеть, что API был вызван и ответ был изменен. trace of test showing api being called and fulfilled

При проверке ответа мы можем увидеть, что наш новый фрукт был добавлен в список. trace of test showing the mock response

Подробнее о продвинутой работе с сетью.

Мокирование с использованием HAR-файлов

HAR-файл — это HTTP Archive файл, который содержит запись всех сетевых запросов, сделанных при загрузке страницы. Он содержит информацию о заголовках запроса и ответа, куки, содержимом, времени и многом другом. Вы можете использовать HAR-файлы для мокирования сетевых запросов в ваших тестах. Вам нужно:

  1. Записать HAR-файл.
  2. Закоммитить HAR-файл вместе с тестами.
  3. Маршрутизировать запросы, используя сохраненные HAR-файлы в тестах.

Запись HAR-файла

Для записи HAR-файла мы используем метод page.route_from_har() или browser_context.route_from_har(). Этот метод принимает путь к HAR-файлу и необязательный объект с опциями. Объект опций может содержать URL, так что только запросы с URL, соответствующим указанному шаблону, будут обслуживаться из HAR-файла. Если не указано, все запросы будут обслуживаться из HAR-файла.

Установка опции update в true создаст или обновит HAR-файл с фактической сетевой информацией вместо обслуживания запросов из HAR-файла. Используйте это при создании теста для заполнения HAR реальными данными.

def test_records_or_updates_the_har_file(page: Page):
# Get the response from the HAR file
page.route_from_har("./hars/fruit.har", url="*/**/api/v1/fruits", update=True)

# Go to the page
page.goto("https://demo.playwright.dev/api-mocking")

# Assert that the fruit is visible
expect(page.get_by_text("Strawberry")).to_be_visible()

Изменение HAR-файла

После того как вы записали HAR-файл, вы можете изменить его, открыв хешированный .txt файл внутри вашей папки 'hars' и отредактировав JSON. Этот файл должен быть закоммичен в вашу систему контроля версий. Каждый раз, когда вы запускаете этот тест с update: true, он будет обновлять ваш HAR-файл с запросом от API.

[
{
"name": "Playwright",
"id": 100
},
// ... другие фрукты
]

Воспроизведение из HAR

Теперь, когда у вас есть записанный HAR-файл и измененные замокированные данные, его можно использовать для обслуживания соответствующих ответов в тесте. Для этого просто отключите или удалите опцию update. Это запустит тест против HAR-файла вместо обращения к API.

def test_gets_the_json_from_har_and_checks_the_new_fruit_has_been_added(page: Page):
# Replay API requests from HAR.
# Either use a matching response from the HAR,
# or abort the request if nothing matches.
page.route_from_har("./hars/fruit.har", url="*/**/api/v1/fruits", update=False)

# Go to the page
page.goto("https://demo.playwright.dev/api-mocking")

# Assert that the Playwright fruit is visible
expect(page.get_by_text("Playwright", exact=True)).to_be_visible()

В трассировке нашего теста мы можем увидеть, что маршрут был выполнен из HAR-файла, и API не был вызван. trace showing the HAR file being used

Если мы проверим ответ, мы увидим, что наш новый фрукт был добавлен в JSON, что было сделано путем ручного обновления хешированного .txt файла внутри папки hars. trace showing response from HAR file

Воспроизведение HAR строго соответствует URL и HTTP-методу. Для POST-запросов также строго соответствуют POST-пейлоады. Если несколько записей соответствуют запросу, выбирается та, у которой больше всего совпадающих заголовков. Запись, приводящая к перенаправлению, будет автоматически следовать.

Аналогично записи, если имя HAR-файла заканчивается на .zip, он считается архивом, содержащим HAR-файл вместе с сетевыми пейлоадами, хранящимися как отдельные записи. Вы также можете извлечь этот архив, отредактировать пейлоады или HAR-лог вручную и указать на извлеченный HAR-файл. Все пейлоады будут разрешены относительно извлеченного HAR-файла в файловой системе.

Запись HAR с помощью CLI

Мы рекомендуем использовать опцию update для записи HAR-файла для вашего теста. Однако вы также можете записать HAR с помощью Playwright CLI.

Откройте браузер с помощью Playwright CLI и передайте опцию --save-har, чтобы создать HAR-файл. При необходимости используйте --save-har-glob, чтобы сохранять только интересующие вас запросы, например, API-эндпоинты. Если имя HAR-файла заканчивается на .zip, артефакты записываются как отдельные файлы и все сжимаются в один zip.

# Сохраните API-запросы с example.com как архив "example.har".
playwright open --save-har=example.har --save-har-glob="**/api/**" https://example.com

Подробнее о продвинутой работе с сетью.

Мокирование WebSockets

Следующий код перехватит WebSocket-соединения и замокирует всю коммуникацию через WebSocket, вместо подключения к серверу. Этот пример отвечает на "request" с "response".

def message_handler(ws: WebSocketRoute, message: Union[str, bytes]):
if message == "request":
ws.send("response")

page.route_web_socket("wss://example.com/ws", lambda ws: ws.on_message(
lambda message: message_handler(ws, message)
))

В качестве альтернативы, вы можете захотеть подключиться к реальному серверу, но перехватывать сообщения между ними и изменять или блокировать их. Вот пример, который изменяет некоторые из сообщений, отправляемых страницей на сервер, и оставляет остальные без изменений.

def message_handler(server: WebSocketRoute, message: Union[str, bytes]):
if message == "request":
server.send("request2")
else:
server.send(message)

def handler(ws: WebSocketRoute):
server = ws.connect_to_server()
ws.on_message(lambda message: message_handler(server, message))

page.route_web_socket("wss://example.com/ws", handler)

Для получения более подробной информации смотрите WebSocketRoute.