Бесконечный скролл — это популярная техника в веб-разработке, позволяющая подгружать новые данные по мере прокрутки страницы пользователем, создавая эффект бесконечной загрузки контента. Эта техника часто используется в социальных сетях, новостных сайтах, интернет-магазинах и других веб-приложениях, где требуется динамически обновлять контент без перезагрузки страницы.
Когда речь заходит о тестировании компонентов с бесконечным скроллом в React, важно не только проверить работоспособность самого механизма скроллинга, но и корректность отображения данных, загрузки новых элементов, а также проверку асинхронных операций.
Для реализации бесконечного скролла в React часто используется
комбинация различных хуков и методов, таких как useState,
useEffect, а также библиотеки для работы с виртуализацией
(например, react-window или
react-virtualized). Основной логикой является отслеживание
текущей позиции скролла и подгрузка новых данных, когда пользователь
достигает нижней границы видимой области.
Пример простого компонента с бесконечным скроллом:
import React, { useState, useEffect } from 'react';
const InfiniteScroll = ({ fetchData, hasMoreData }) => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
const handleScroll = () => {
if (
window.innerHeight + document.documentElement.scrollTop
=== document.documentElement.offsetHeight
&& !loading && hasMoreData
) {
setLoading(true);
fetchData().then(newData => {
setData(prevData => [...prevData, ...newData]);
setLoading(false);
});
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [loading, fetchData, hasMoreData]);
return (
<div>
{data.map((item, index) => (
<div key={index}>{item}</div>
))}
{loading && <div>Loading...</div>}
</div>
);
};
export default InfiniteScroll;
В этом примере компонент загружает данные по мере прокрутки до конца страницы, добавляя их в состояние и отображая в списке.
Тестирование компонентов, использующих бесконечный скролл, требует особого подхода. Основные задачи, которые нужно решить в тестах:
Для тестирования компонентов React с использованием React Testing Library важно уделить внимание событиям, состояниям и асинхронным операциям.
Для работы с асинхронными данными важно правильно настроить среду.
Для имитации асинхронных вызовов можно использовать
jest.mock() для подмены реальных API-запросов или же
использовать фиктивные данные. Также полезно добавить обработку времени
с помощью jest.useFakeTimers().
React Testing Library предоставляет удобные инструменты для имитации событий прокрутки. Важно прокачать тест таким образом, чтобы скроллинг был проверен с учетом динамической загрузки контента.
Пример теста с прокруткой:
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import InfiniteScroll from './InfiniteScroll';
test('загружает новые данные при прокрутке до конца', async () => {
const fetchData = jest.fn().mockResolvedValue([1, 2, 3]);
const { container } = render(<InfiniteScroll fetchData={fetchData} hasMoreData={true} />);
// Прокрутка до конца страницы
fireEvent.scroll(container, { target: { scrollY: 1000 } });
// Ожидание завершения асинхронной загрузки
await waitFor(() => expect(fetchData).toHaveBeenCalledTimes(1));
// Проверка отображения загруженных данных
expect(screen.getByText('1')).toBeInTheDocument();
expect(screen.getByText('2')).toBeInTheDocument();
expect(screen.getByText('3')).toBeInTheDocument();
});
В этом тесте проверяется, что при прокрутке страницы вызывается
функция fetchData для подгрузки новых данных. После этого
проверяется, что новые данные отображаются на экране.
Для тестирования состояния загрузки можно использовать элементы UI, такие как индикатор загрузки. Например, можно проверить, что индикатор появляется при подгрузке новых данных.
Пример:
test('показывает индикатор загрузки при загрузке новых данных', async () => {
const fetchData = jest.fn().mockResolvedValue([4, 5, 6]);
render(<InfiniteScroll fetchData={fetchData} hasMoreData={true} />);
// Прокрутка до конца
fireEvent.scroll(window, { target: { scrollY: 1000 } });
// Проверка, что индикатор загрузки появился
expect(screen.getByText('Loading...')).toBeInTheDocument();
// Ожидание завершения асинхронной загрузки
await waitFor(() => expect(fetchData).toHaveBeenCalledTimes(1));
// Проверка, что индикатор загрузки исчез
expect(screen.queryByText('Loading...')).toBeNull();
});
Здесь проверяется, что во время подгрузки данных появляется индикатор “Loading…”, а после завершения загрузки — исчезает.
Так как данные подгружаются асинхронно, важно использовать
waitFor или findBy из React Testing Library
для корректного ожидания завершения асинхронных операций.
test('проверка асинхронной загрузки данных', async () => {
const fetchData = jest.fn().mockResolvedValue([7, 8, 9]);
render(<InfiniteScroll fetchData={fetchData} hasMoreData={true} />);
// Прокрутка до конца
fireEvent.scroll(window, { target: { scrollY: 1000 } });
// Ожидание завершения асинхронного вызова
const item7 = await screen.findByText('7');
const item8 = await screen.findByText('8');
const item9 = await screen.findByText('9');
expect(item7).toBeInTheDocument();
expect(item8).toBeInTheDocument();
expect(item9).toBeInTheDocument();
});
В этом тесте используется findByText для ожидания
появления загруженных элементов.
Правильное тестирование компонентов с бесконечным скроллом помогает обеспечить их стабильность и предсказуемость поведения в реальных условиях.