Вопрос или проблема
У меня есть пользовательский хук, который получает данные из стороннего 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-вызовы внутри вашего хука. Давайте создадим тест, который:
- Проверяет, что данные были успешно получены.
- Обрабатывает ошибки в случае неудачи.
Пример теста
Пример реализации теста может выглядеть следующим образом:
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
, вы можете эффективно имитировать сетевые запросы и проверять различные сценарии: успешные ответы и ошибки.
Данная методология позволяет создавать надежные и предсказуемые тесты, которые значительно упрощают отладку и поддержание кода приложения.