Мокирование fetch и axios

Тестирование компонентов и логики в JavaScript, которые выполняют асинхронные запросы, требует мокирования HTTP-запросов. Библиотеки, такие как fetch и axios, часто используются для работы с API. Мокирование этих запросов позволяет изолировать тесты от реальных серверных зависимостей, повышая скорость тестов и стабильность среды.

В Enzyme, вместе с Jest, мокирование HTTP-запросов — это неотъемлемая часть настройки тестов, особенно если компоненты или функции взаимодействуют с внешними API.

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

fetch — это стандартный метод для выполнения HTTP-запросов в современных браузерах. В тестах важно предотвратить реальное выполнение запросов, заменив их моками. Мокирование позволяет контролировать поведение запросов, а также задавать имитацию ответов с серверов.

Простое мокирование fetch:

Jest предоставляет встроенную функцию jest.fn(), которая позволяет заменить вызовы fetch на моки. Для этого достаточно использовать метод global.fetch.

beforeAll(() => {
  global.fetch = jest.fn(() =>
    Promise.resolve({
      json: () => Promise.resolve({ data: 'test' }),
    })
  );
});

it('должен вызвать fetch и вернуть данные', async () => {
  const response = await fetch('/api/data');
  const data = await response.json();

  expect(fetch).toHaveBeenCalledTimes(1);
  expect(data.data).toBe('test');
});

В данном примере мы заменили глобальный fetch на мок, который всегда возвращает успешный ответ с данными { data: 'test' }. Тест проверяет, что fetch был вызван и данные были правильно извлечены.

Мокирование с ошибкой:

Можно также имитировать ошибки, которые могут возникать при запросах, например, если сервер недоступен или произошла ошибка на стороне API.

beforeAll(() => {
  global.fetch = jest.fn(() =>
    Promise.reject(new Error('Network error'))
  );
});

it('должен обрабатывать ошибку при вызове fetch', async () => {
  try {
    await fetch('/api/data');
  } catch (e) {
    expect(e.message).toBe('Network error');
  }
});

Здесь мы подменяем fetch на мок, который всегда вызывает ошибку. Тест проверяет, что ошибка корректно обрабатывается.

Проверка параметров запроса:

Когда необходимо проверить, с какими параметрами был вызван fetch, можно использовать expect для утверждений.

beforeAll(() => {
  global.fetch = jest.fn(() =>
    Promise.resolve({
      json: () => Promise.resolve({ data: 'test' }),
    })
  );
});

it('должен передавать правильные параметры в fetch', async () => {
  await fetch('/api/data', {
    method: 'POST',
    body: JSON.stringify({ id: 1 }),
  });

  expect(fetch).toHaveBeenCalledWith(
    '/api/data',
    expect.objectContaining({
      method: 'POST',
      body: JSON.stringify({ id: 1 }),
    })
  );
});

Здесь мы проверяем, что fetch был вызван с правильными параметрами — методом POST и телом запроса, сериализованным в JSON.

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

axios — это популярная библиотека для выполнения HTTP-запросов, которая часто используется в React-компонентах и других JavaScript-приложениях. Мокирование axios имеет свои особенности, но в целом процесс схож с мокированием fetch.

Простое мокирование axios:

Для мокирования axios можно использовать jest.mock для замены всей библиотеки на поддельную реализацию, которая возвращает заранее заданные данные.

import axios from 'axios';

jest.mock('axios');

it('должен делать запрос с axios и возвращать данные', async () => {
  axios.get.mockResolvedValue({ data: { message: 'test' } });

  const response = await axios.get('/api/data');

  expect(axios.get).toHaveBeenCalledWith('/api/data');
  expect(response.data.message).toBe('test');
});

В данном примере мы заменяем вызов axios.get на моку, которая всегда возвращает данные с полем message, равным ‘test’. Тест проверяет, что запрос был выполнен и данные были корректно возвращены.

Мокирование с ошибкой:

Для имитации ошибки при запросе через axios используется метод mockRejectedValue, который позволяет задавать отклонённые промисы.

import axios from 'axios';

jest.mock('axios');

it('должен обрабатывать ошибку с axios', async () => {
  axios.get.mockRejectedValue(new Error('Network error'));

  try {
    await axios.get('/api/data');
  } catch (e) {
    expect(e.message).toBe('Network error');
  }
});

Здесь мы подменяем axios.get на мок, который вызывает ошибку с сообщением ‘Network error’. В тесте проверяется корректная обработка этой ошибки.

Проверка параметров запроса:

Так же, как и с fetch, можно проверять параметры запроса, переданные в axios.

import axios from 'axios';

jest.mock('axios');

it('должен передавать правильные параметры в axios', async () => {
  await axios.post('/api/data', { id: 1 });

  expect(axios.post).toHaveBeenCalledWith('/api/data', { id: 1 });
});

Тест проверяет, что при вызове axios.post с данными { id: 1 }, метод был вызван с правильными параметрами.

Мокирование с использованием msw

Если проект требует более сложного мокирования HTTP-запросов или симуляции поведения реального сервера, можно использовать библиотеку msw (Mock Service Worker). Эта библиотека позволяет имитировать серверные ответы на уровне Service Worker, что делает мокирование более гибким и реалистичным.

import { rest } from 'msw';
import { server } from './server'; // конфигурация MSW

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

it('должен обработать запрос через MSW', async () => {
  server.use(
    rest.get('/api/data', (req, res, ctx) => {
      return res(ctx.json({ message: 'test' }));
    })
  );

  const response = await fetch('/api/data');
  const data = await response.json();

  expect(data.message).toBe('test');
});

В этом примере создаётся сервер с помощью MSW, который перехватывает HTTP-запросы и отвечает заданными данными. Это особенно полезно для тестирования сложных сценариев с асинхронными запросами и сложными ответами от API.

Сравнение подходов

  • Мокирование fetch подходит для более простых случаев, когда нужно просто заменить глобальную функцию и контролировать её поведение.
  • Мокирование axios — это полезный способ тестировать запросы через популярную библиотеку, предлагающую более удобный API для работы с HTTP.
  • MSW предоставляет более продвинутый способ мокирования, позволяя симулировать реальный сервер и более гибко работать с асинхронными запросами.

Все эти подходы могут использоваться в зависимости от требований тестируемого приложения и сложности взаимодействия с сервером.