Мокирование API-запросов — это подмена реального сетевого ответа заранее заготовленным, без обращения к настоящему бэкенду. В Playwright это делается через page.route(): тест перехватывает запрос браузера к определённому URL и вместо реального похода на сервер отдаёт свой ответ. Это нужно, когда тест должен проверить конкретный сценарий (пустой список, ошибку сервера, медленный ответ), который сложно или нестабильно воспроизвести на реальном бэкенде, а также когда UI-тест не должен зависеть от того, жив ли бэкенд прямо сейчас.
Базовое мокирование через route + fulfill
await page.route('**/api/users', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([
{ id: 1, name: 'Анна' },
{ id: 2, name: 'Игорь' },
]),
});
});
await page.goto('/users');
await expect(page.getByText('Анна')).toBeVisible();
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([
{ id: 1, name: 'Анна' },
{ id: 2, name: 'Игорь' },
]),
});
});
await page.goto('/users');
await expect(page.getByText('Анна')).toBeVisible();
page.route(url, handler) подписывается на все запросы, совпадающие с паттерном URL (здесь **/api/users — маска с wildcard, совпадёт с любым путём, заканчивающимся на /api/users). Внутри обработчика route.fulfill() завершает запрос собственным ответом: статус-код, заголовки, тело. Браузер не отправляет запрос на реальный сервер — Playwright перехватывает его на уровне сетевого слоя раньше, чем он уйдёт из процесса браузера.
Мокирование ошибки сервера
await page.route('**/api/users', (route) =>
route.fulfill({
status: 500,
contentType: 'application/json',
body: JSON.stringify({ error: 'Internal Server Error' }),
})
);
await page.goto('/users');
await expect(page.getByText('Не удалось загрузить пользователей')).toBeVisible();
route.fulfill({
status: 500,
contentType: 'application/json',
body: JSON.stringify({ error: 'Internal Server Error' }),
})
);
await page.goto('/users');
await expect(page.getByText('Не удалось загрузить пользователей')).toBeVisible();
Так проверяется поведение интерфейса при отказе бэкенда — то, что на реальном сервере специально не воспроизвести без его ручной поломки. Тест детерминированно получает код 500 и проверяет, что приложение показывает понятное сообщение об ошибке, а не белый экран или необработанное исключение в консоли.
Частичная подмена: route.fetch() + fulfill() с изменениями
await page.route('**/api/config', async (route) => {
const response = await route.fetch();
const json = await response.json();
json.featureFlags.newCheckout = true;
await route.fulfill({ response, json });
});
const response = await route.fetch();
const json = await response.json();
json.featureFlags.newCheckout = true;
await route.fulfill({ response, json });
});
Не всегда нужно полностью выдумывать ответ — иногда полезнее взять реальный ответ сервера и точечно изменить в нём одно поле. route.fetch() выполняет настоящий запрос к серверу и возвращает реальный ответ, который можно разобрать и модифицировать перед тем, как отдать его странице через route.fulfill({ response, json }). Это способ включить конкретный feature flag или подставить тестовые данные, не теряя остальную реальную структуру ответа.
Отличие route от мока на уровне бэкенда
Мокирование через page.route() происходит на уровне браузера, в котором выполняется тест — реальный бэкенд в этот момент может даже не запускаться. Это отличается от подхода, когда тестовое окружение бэкенда настраивается заранее (тестовая БД с фикстурами, тестовый инстанс сервиса): там запросы реальные, но данные на сервере подготовлены под тест. page.route() быстрее и не требует поднятого бэкенда вообще, но не проверяет, что реальный API действительно так себя ведёт — контракт между фронтендом и бэкендом при этом подходе нужно проверять отдельно (например, интеграционными или контрактными тестами).
Частые вопросы про мокирование API в Playwright
Чем route.fulfill() отличается от route.continue()? route.fulfill() полностью подменяет ответ — запрос до сервера вообще не доходит. route.continue() пропускает запрос дальше (к реальному серверу), но позволяет по пути изменить его параметры — заголовки, тело, URL.
Можно ли замокать не все запросы к API, а только конкретный? Да, паттерн в page.route() можно сделать максимально точным — вплоть до конкретного URL с параметрами, а не маски с wildcard. Чем точнее паттерн, тем меньше риск случайно замокать не тот запрос.
Нужен ли реальный бэкенд для тестов с page.route()? Нет, если мокируются все нужные запросы — тест может работать полностью без поднятого бэкенда. Но тогда стоит отдельно поддерживать проверку того, что реальный API возвращает данные в том же формате, что и моки, иначе они разойдутся незаметно.
Когда мокирование API не подходит, и лучше использовать реальный бэкенд? Когда важно проверить именно интеграцию — что фронтенд и бэкенд реально совместимы. Мокирование хорошо для проверки поведения интерфейса на разных данных, но не заменяет end-to-end тесты с настоящим сервером на критичных сценариях.
Можно ли замокать не все запросы к API, а только конкретный? Да, паттерн в page.route() можно сделать максимально точным — вплоть до конкретного URL с параметрами, а не маски с wildcard. Чем точнее паттерн, тем меньше риск случайно замокать не тот запрос.
Нужен ли реальный бэкенд для тестов с page.route()? Нет, если мокируются все нужные запросы — тест может работать полностью без поднятого бэкенда. Но тогда стоит отдельно поддерживать проверку того, что реальный API возвращает данные в том же формате, что и моки, иначе они разойдутся незаметно.
Когда мокирование API не подходит, и лучше использовать реальный бэкенд? Когда важно проверить именно интеграцию — что фронтенд и бэкенд реально совместимы. Мокирование хорошо для проверки поведения интерфейса на разных данных, но не заменяет end-to-end тесты с настоящим сервером на критичных сценариях.
Закрепить мокирование API на практике
Разница между тестом на моках и на реальном бэкенде яснее всего на своём проекте. Бесплатный тренажёр Playwright Arena — для основ. Для разбора моков и API-тестов в реальной архитектуре — курс «Автотестирование JS/TS + Playwright» в Quality Academy.
-------
Полезные ссылки школы
Сайт Quality Academy:
/main
Telegram-канал:
https://t.me/quality_academy
YouTube-канал:
https://www.youtube.com/@quality_academy
ВКонтакте:
https://vk.com/quality_academy
Канал отзывов учеников (58+ отзывов):
https://t.me/quality_academy_reviews
Задать вопрос менеджеру:
https://t.me/quality_academy_bot
Тест «Подойдёт ли вам тестирование»:
https://quiz.quality-academy.ru
5000+ вопросов с собесов тестировщика — бот-тренажёр:
https://t.me/quality_academy_interview_bot
3 практические задачи и дорожная карта:
https://t.me/quality_academy_tasks_bot
Бесплатные тренажёры — SQL Arena, Playwright Arena, Python Arena:
SQL Arena · Playwright Arena · Python Arena
/main
Telegram-канал:
https://t.me/quality_academy
YouTube-канал:
https://www.youtube.com/@quality_academy
ВКонтакте:
https://vk.com/quality_academy
Канал отзывов учеников (58+ отзывов):
https://t.me/quality_academy_reviews
Задать вопрос менеджеру:
https://t.me/quality_academy_bot
Тест «Подойдёт ли вам тестирование»:
https://quiz.quality-academy.ru
5000+ вопросов с собесов тестировщика — бот-тренажёр:
https://t.me/quality_academy_interview_bot
3 практические задачи и дорожная карта:
https://t.me/quality_academy_tasks_bot
Бесплатные тренажёры — SQL Arena, Playwright Arena, Python Arena:
SQL Arena · Playwright Arena · Python Arena