Как мне замокировать пользовательский хуком с axios для тестирования?

Вопрос или проблема

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

Если кто-то может помочь, буду очень признателен. Я включил хук ниже.

Вот как вызывается хук…

const { data, error, loading } = useFetch({ url: 'https://api.some_url.com/search?q=', query: 'некоторый поисковый запрос' });

Это пользовательский хук useFetch…

import { useEffect, useState } from 'react';

type FetchParams = {
  url: string;
  query: string;
};

export function useFetch(props: FetchParams) {
  const { url, query } = props;
  const [data, setData] = useState([]);
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchUrl: string = `${url}${query}`;

    const fetchData = async () => {
      setLoading(true);

      await fetch(fetchUrl)
        .then((response) => response.json())
        .then((response) => {
          setLoading(false);
          setData(response.data);
        })
        .catch((error) => {
          setLoading(false);
          setError(error);
        });
    };

    fetchData();
  }, [url, query]);

  return { data, error, loading };
}

Ответ или решение

Как замокировать пользовательский хук с axios для тестирования

Введение

В тестировании пользовательских хуков в React, особенно когда они зависят от сетевых запросов, возникает необходимость в замене (мокировании) API-вызовов. Это позволяет проверять функциональность без реальных запросов к серверу, что делает тесты более надежными и быстрыми. В этой статье мы рассмотрим, как замокировать пользовательский хук useFetch, который использует fetch для получения данных с удаленного API. Мы также интегрируем библиотеку для тестирования vitest, чтобы уверенно реализовать мокирование.

Описание пользовательского хука

Перед тем как перейти к тестированию, давайте вспомним основную структуру нашего пользовательского хука:

import { useEffect, useState } from 'react';

type FetchParams = {
  url: string;
  query: string;
};

export function useFetch(props: FetchParams) {
  const { url, query } = props;
  const [data, setData] = useState([]);
  const [error, setError] = useState<string>('');
  const [loading, setLoading] = useState<boolean>(false);

  useEffect(() => {
    const fetchUrl: string = `${url}${query}`;

    const fetchData = async () => {
      setLoading(true);

      await fetch(fetchUrl)
        .then((response) => response.json())
        .then((response) => {
          setLoading(false);
          setData(response.data);
        })
        .catch((error) => {
          setLoading(false);
          setError(error);
        });
    };

    fetchData();
  }, [url, query]);

  return { data, error, loading };
}

Подготовка к тестированию с помощью vitest

Для начала вам необходимо убедиться, что у вас установлены пакеты vitest и @testing-library/react. Если они еще не установлены, выполните команду:

npm install --save-dev vitest @testing-library/react

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

Мы можем использовать функцию vi.mock из vitest для того, чтобы замокировать API-вызовы внутри вашего хука. Давайте создадим тест, который:

  1. Проверяет, что данные были успешно получены.
  2. Обрабатывает ошибки в случае неудачи.

Пример теста

Пример реализации теста может выглядеть следующим образом:

import { renderHook } from '@testing-library/react-hooks';
import { useFetch } from './useFetch'; // импортируем наш хук
import { vi } from 'vitest';

// Мокируем fetch
global.fetch = vi.fn();

describe('useFetch', () => {
  beforeEach(() => {
    vi.clearAllMocks(); // очищаем моки перед каждым тестом
  });

  it('должен возвращать данные при успешном запросе', async () => {
    // Мок данных, которые будут возвращены
    const mockResponse = { data: [{ id: 1, name: 'Test Data' }] };
    (fetch as jest.Mock).mockResolvedValueOnce({
      json: jest.fn().mockResolvedValueOnce(mockResponse),
    });

    const { result, waitForNextUpdate } = renderHook(() =>
      useFetch({ url: 'https://api.some_url.com/search?q=', query: 'some search term' })
    );

    // Ожидаем обновлений состояния
    await waitForNextUpdate();

    // Проверяем состояние
    expect(result.current.data).toEqual(mockResponse.data);
    expect(result.current.error).toBe('');
    expect(result.current.loading).toBe(false);
  });

  it('должен обрабатывать ошибки', async () => {
    (fetch as jest.Mock).mockRejectedValueOnce(new Error('Network error'));

    const { result, waitForNextUpdate } = renderHook(() =>
      useFetch({ url: 'https://api.some_url.com/search?q=', query: 'some search term' })
    );

    await waitForNextUpdate();

    expect(result.current.data).toEqual([]);
    expect(result.current.error).toBeInstanceOf(Error);
    expect(result.current.loading).toBe(false);
  });
});

Заключение

Создание тестов для пользовательских хуков, которые используют API, требует правильного подхода к мокированию и обработке ожиданий. Используя vitest и функцию vi.mock, вы можете эффективно имитировать сетевые запросы и проверять различные сценарии: успешные ответы и ошибки.

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

Оцените материал
Добавить комментарий

Капча загружается...