Mock Server Pattern

Mock Server Pattern — это подход к тестированию, при котором реальные HTTP-запросы заменяются заранее определёнными ответами (моками). Он позволяет изолировать фронтенд от бэкенда, ускоряет тесты и делает их предсказуемыми. В Playwright этот паттерн реализуется через перехват сетевых запросов с помощью API page.route().


Перехват и подмена запросов

Базовый принцип заключается в том, чтобы перехватывать запросы на определённые URL и подставлять ответ, который ожидается в тесте. Пример:

import { test, expect } from '@playwright/test';

test('Mock API response', async ({ page }) => {
  await page.route('**/api/users', route =>
    route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify([{ id: 1, name: 'Alice' }])
    })
  );

  await page.goto('https://example.com/users');
  const userName = await page.textContent('.user-name');
  expect(userName).toBe('Alice');
});

Ключевые моменты:

  • Использование шаблона URL **/api/users позволяет перехватывать любые запросы к этому endpoint.
  • route.fulfill() полностью заменяет ответ сервера, включая статус, заголовки и тело.
  • Mock позволяет тестировать UI независимо от состояния реального API.

Моки на основе файлов

Для упрощения поддержки большого количества сценариев часто используют JSON-файлы с ответами. Это делает тесты более читаемыми и масштабируемыми:

import fs from 'fs';
import { test } from '@playwright/test';

test('Load users from mock file', async ({ page }) => {
  const mockData = fs.readFileSync('mocks/users.json', 'utf-8');

  await page.route('**/api/users', route =>
    route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: mockData
    })
  );

  await page.goto('https://example.com/users');
});

Преимущества такого подхода:

  • Централизованное хранение моков.
  • Легко изменять данные без правки тестов.
  • Позволяет создавать сложные сценарии с множеством вариантов ответа.

Динамические ответы

Иногда требуется возвращать ответы, зависящие от запроса. Playwright позволяет реализовать динамическое мокирование:

await page.route('**/api/users/*', route => {
  const userId = route.request().url().split('/').pop();
  route.fulfill({
    status: 200,
    contentType: 'application/json',
    body: JSON.stringify({ id: Number(userId), name: `User ${userId}` })
  });
});

Особенности:

  • Использование route.request() позволяет анализировать URL, метод и тело запроса.
  • Мок можно настроить под различные сценарии без создания отдельных файлов.

Эмуляция задержки и ошибок

Mock Server Pattern не ограничивается только успешными ответами. Можно симулировать задержки, таймауты и ошибки:

await page.route('**/api/users', async route => {
  await new Promise(resolve => setTimeout(resolve, 1000));
  route.fulfill({
    status: 500,
    contentType: 'application/json',
    body: JSON.stringify({ error: 'Internal Server Error' })
  });
});

Использование задержек и ошибок позволяет:

  • Проверять поведение UI при долгих ответах сервера.
  • Тестировать обработку ошибок и уведомления для пользователя.
  • Исключить зависимость теста от реального API.

Совместное использование с page.waitForResponse()

Mock Server Pattern хорошо сочетается с методами ожидания Playwright, что позволяет убедиться, что приложение корректно обрабатывает ответ:

const [response] = await Promise.all([
  page.waitForResponse('**/api/users'),
  page.click('button.load-users')
]);

expect(response.status()).toBe(200);
const data = await response.json();
expect(data.length).toBeGreaterThan(0);

Преимущество: проверка как UI, так и фактического ответа одновременно.


Организация больших наборов моков

Для крупных проектов удобно создавать отдельный слой моков:

mocks/
├─ users.json
├─ products.json
└─ orders.json

И подключать их динамически в тестах:

import * as usersMock from '../mocks/users.json';

await page.route('**/api/users', route =>
  route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(usersMock) })
);

Рекомендации по организации:

  • Использовать отдельные файлы для каждого endpoint.
  • Разделять успешные и ошибочные ответы.
  • Создавать версии моков под разные сценарии (пустой список, один элемент, полный набор).

Сочетание с сетевыми снифферами

Playwright позволяет комбинировать Mock Server Pattern с логированием запросов. Это помогает проверять, какие запросы реально уходят на сервер, даже если большинство ответов подменены:

page.on('request', request => {
  console.log('Request:', request.method(), request.url());
});

Это особенно полезно при тестировании сложных сценариев с несколькими запросами, где важно убедиться, что фронтенд отправляет корректные данные.


Итоговые преимущества использования Mock Server Pattern

  • Полная независимость тестов от внешнего API.
  • Ускорение тестового прогонного времени.
  • Лёгкая настройка сценариев ошибок и задержек.
  • Централизованное управление тестовыми данными.

Этот паттерн является фундаментальной практикой для надёжного E2E тестирования в Playwright и позволяет создавать предсказуемые, стабильные и масштабируемые тестовые сценарии.