Skip to main content

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

Введение

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

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

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

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 никогда не вызывался, однако он был выполнен с использованием мокированных данных. трассировка мокирования api

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

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

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

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

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 был вызван и ответ был изменен. трассировка теста, показывающая вызов и выполнение api

При проверке ответа видно, что наш новый фрукт был добавлен в список. трассировка теста, показывающая мокированный ответ

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

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

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

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

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

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

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

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-файла

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

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

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

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

Если мы проверим ответ, мы увидим, что наш новый фрукт был добавлен в JSON, что было сделано путем ручного обновления хешированного .txt файла внутри папки hars. трассировка, показывающая ответ из HAR-файла

Воспроизведение 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".
npx playwright open --save-har=example.har --save-har-glob="**/api/**" https://example.com

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

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

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

await page.routeWebSocket('wss://example.com/ws', ws => {
ws.onMessage(message => {
if (message === 'request')
ws.send('response');
});
});

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

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].