MSW (Mock Service Worker) основы

MSW (Mock Service Worker) — это библиотека для имитации сетевых запросов в браузере и Node.js. Она позволяет перехватывать HTTP-запросы на уровне Service Worker и возвращать заранее заданные ответы, что делает тестирование компонентов и API-зависимого функционала максимально предсказуемым и изолированным от реального сервера.

Установка и настройка

Для начала необходимо установить пакет:

npm install msw --save-dev

Создаются два ключевых файла: handlers.js и server.js (для Node) или browser.js (для фронтенда).

Пример handlers.js:

import { rest } from 'msw';

export const handlers = [
  rest.get('/api/users', (req, res, ctx) => {
    return res(
      ctx.status(200),
      ctx.json([
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' }
      ])
    );
  }),
  rest.post('/api/login', (req, res, ctx) => {
    const { username } = req.body;
    if (username === 'admin') {
      return res(ctx.status(200), ctx.json({ token: '12345' }));
    } else {
      return res(ctx.status(403), ctx.json({ error: 'Forbidden' }));
    }
  })
];

Настройка для Node.js (server.js):

import { setupServer } from 'msw/node';
import { handlers } from './handlers';

export const server = setupServer(...handlers);

Настройка для браузера (browser.js):

import { setupWorker } from 'msw';
import { handlers } from './handlers';

export const worker = setupWorker(...handlers);

Интеграция с React Testing Library

При тестировании компонентов React необходимо обеспечить корректный жизненный цикл mock-сервера. Обычно используют хуки Jest:

import { server } from './server';
import { render, screen, waitFor } from '@testing-library/react';
import UserList from './UserList';

// Включение перехвата запросов до всех тестов
beforeAll(() => server.listen());
// Сброс обработчиков после каждого теста
afterEach(() => server.resetHandlers());
// Отключение сервера после всех тестов
afterAll(() => server.close());

test('отображает список пользователей', async () => {
  render(<UserList />);
  
  await waitFor(() => {
    expect(screen.getByText('Alice')).toBeInTheDocument();
    expect(screen.getByText('Bob')).toBeInTheDocument();
  });
});

Изменение ответов в тестах

MSW позволяет изменять поведение mock-сервера прямо в тестах для проверки ошибок или разных сценариев:

import { rest } from 'msw';
import { server } from './server';

test('обрабатывает ошибку сервера', async () => {
  server.use(
    rest.get('/api/users', (req, res, ctx) => {
      return res(ctx.status(500), ctx.json({ error: 'Internal Server Error' }));
    })
  );

  render(<UserList />);
  
  await waitFor(() => {
    expect(screen.getByText(/ошибка/i)).toBeInTheDocument();
  });
});

Особенности работы с асинхронностью

Компоненты React часто зависят от асинхронных запросов. MSW идеально интегрируется с async/await и методами React Testing Library (waitFor, findBy*):

const button = screen.getByRole('button', { name: /загрузить/i });
fireEvent.click(button);

const userItem = await screen.findByText('Alice'); // автоматически ждёт появления
expect(userItem).toBeInTheDocument();

Совместимость с Node и браузером

MSW позволяет одинаково тестировать как фронтенд, так и серверные функции, вызывающие API. Для Node используется setupServer, для браузера — setupWorker. Это гарантирует одинаковое поведение тестов и минимизирует зависимость от внешних API.

Практические рекомендации

  • Разделять обработчики по модулям API для удобного сопровождения.
  • Использовать resetHandlers() после каждого теста, чтобы тесты были полностью независимыми.
  • Тестировать сценарии ошибок и задержек с помощью ctx.status и ctx.delay().
  • Подключать MSW на раннем этапе приложения, если тестируется интеграция с реальным UI.

Преимущества MSW

  1. Точные имитации сетевых запросов на уровне Service Worker.
  2. Возможность тестирования любых сценариев API без обращения к реальному серверу.
  3. Лёгкая интеграция с React Testing Library и Jest.
  4. Поддержка как клиентских, так и серверных тестов.

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