0Pricing
React Academy · Урок

Тестирование асинхронного интерфейса и вызовов API с MSW

Имитационно обрабатывайте HTTP-запросы с помощью Mock Service Worker, чтобы тестировать компоненты, получающие данные.

«Тестирование асинхронного интерфейса и вызовов API с MSW» — бесплатный урок React Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Academy содержит 4 уроков всего.

Зачем нужен Mock Service Worker

MSW перехватывает HTTP-запросы на уровне сети с помощью сервис-воркера в браузере или перехватчика http в Node, позволяя имитировать API без изменений в коде приложения.

Установка MSW

Установите MSW и настройте перехватчик Node для тестов Jest и Vitest.

// npm install msw --save-dev

// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('/api/users', () => {
    return HttpResponse.json([{ id: 1, name: 'Alice' }]);
  }),
];

Настройка имитационного сервера

Создайте экземпляр setupServer со своими обработчиками и вызывайте server.listen() перед тестами, server.resetHandlers() после каждого теста и server.close() после всех тестов.

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

const server = setupServer(...handlers);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

Проверка компонента, выполняющего запросы

Отобразите компонент, который выполняет запрос. MSW перехватит запрос и вернёт имитационные данные. Проверьте, что видит пользователь после загрузки данных.

test('shows user list after fetch', async () => {
  render(<UserList />);
  expect(screen.getByText('Loading...')).toBeInTheDocument();
  expect(await screen.findByText('Alice')).toBeInTheDocument();
});

Запросы findBy для асинхронного интерфейса

Запросы findBy возвращают обещание, которое выполняется при появлении элемента, — по умолчанию в течение тайм-аута до 1 секунды. Используйте их для содержимого, появляющегося после асинхронных операций.

// findByText waits for the element to appear
const username = await screen.findByText('Alice');
expect(username).toBeInTheDocument();

// waitFor wraps assertions that need to wait
await waitFor(() => {
  expect(screen.getByText('3 users')).toBeInTheDocument();
});

Переопределение обработчиков для отдельного теста

Используйте server.use() внутри теста, чтобы добавить одноразовый обработчик, переопределяющий стандартный только для этого теста.

test('shows error on API failure', async () => {
  server.use(
    http.get('/api/users', () => {
      return HttpResponse.json({ message: 'Server error' }, { status: 500 });
    })
  );

  render(<UserList />);
  expect(await screen.findByText('Failed to load users')).toBeInTheDocument();
});

Проверка состояний загрузки

Проверьте индикатор загрузки сразу после рендеринга, синхронно, до поступления асинхронных данных.

test('shows loading state initially', () => {
  render(<UserList />);
  expect(screen.getByRole('progressbar')).toBeInTheDocument();
  // or
  expect(screen.getByText('Loading...')).toBeInTheDocument();
});

Тестирование запросов POST

Определите обработчик POST, который проверяет тело запроса и возвращает созданный ресурс. Проверьте, что компонент отражает состояние успешного выполнения.

server.use(
  http.post('/api/users', async ({ request }) => {
    const body = await request.json();
    return HttpResponse.json({ id: 2, ...body }, { status: 201 });
  })
);

test('creates a user', async () => {
  const user = userEvent.setup();
  render(<NewUserForm />);
  await user.type(screen.getByLabelText('Name'), 'Bob');
  await user.click(screen.getByRole('button', { name: /create/i }));
  expect(await screen.findByText('User created!')).toBeInTheDocument();
});

Задержки сети для реалистичных тестов

Добавьте к обработчикам искусственные задержки, чтобы тщательнее проверять интерфейс загрузки, используя утилиту delay MSW.

import { delay } from 'msw';

http.get('/api/users', async () => {
  await delay(200);
  return HttpResponse.json([{ id: 1, name: 'Alice' }]);
})

Тестирование с React Query

Оборачивайте компонент в новый QueryClientProvider для каждого теста, чтобы состояние не переходило между тестами.

function renderWithQuery(ui: React.ReactElement) {
  const queryClient = new QueryClient({
    defaultOptions: { queries: { retry: false } },
  });
  return render(
    <QueryClientProvider client={queryClient}>{ui}</QueryClientProvider>
  );
}

Проверка данных запроса

Используйте шпион запросов внутри обработчика, чтобы проверить, что приложение отправило правильное тело запроса или заголовки.

let capturedBody: unknown;

server.use(
  http.post('/api/login', async ({ request }) => {
    capturedBody = await request.json();
    return HttpResponse.json({ token: 'abc' });
  })
);

test('sends credentials to API', async () => {
  // ... submit form ...
  expect(capturedBody).toEqual({ email: 'a@b.com', password: 'pass' });
});

MSW в браузере при разработке

MSW также работает в браузере во время разработки. Выполните npx msw init public/, чтобы установить сервис-воркер, и импортируйте обработчики в main.tsx, чтобы использовать имитационный API при локальной разработке.

Быстрая проверка

Какой тип запроса RTL следует использовать, чтобы проверить содержимое, появляющееся после завершения вызова API?

Итоги

MSW перехватывает реальные HTTP-запросы, поэтому тесты остаются реалистичными и не обращаются к работающему серверу. Используйте server.use(), чтобы переопределять обработчики для отдельных тестов, findBy для асинхронных проверок и оборачивайте тесты React Query в новый QueryClientProvider.

Часто задаваемые вопросы

Урок «Тестирование асинхронного интерфейса и вызовов API с MSW» бесплатный?

Да — полный текст урока «Тестирование асинхронного интерфейса и вызовов API с MSW» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Academy, подпишись на CoddyKit PRO. Курс React Academy содержит 4 уроков всего.

Чему я научусь в уроке «Тестирование асинхронного интерфейса и вызовов API с MSW»?

Имитационно обрабатывайте HTTP-запросы с помощью Mock Service Worker, чтобы тестировать компоненты, получающие данные. Ты практикуешь React Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать React Academy?

Предыдущий опыт не требуется. React Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Тестирование асинхронного интерфейса и вызовов API с MSW»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке React Academy?

Да. Каждый урок React Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Интеграционное тестирование с React Testing Library
  2. Тестирование асинхронного интерфейса и вызовов API с MSW
  3. Начало работы с Playwright для React
  4. Сквозное тестирование форм и пользовательских сценариев
← Назад к React Academy