Обновление элементов в списке
В React часто возникает необходимость обновления элементов внутри списка. При тестировании таких компонентов важно учитывать различные аспекты, такие как рендеринг новых элементов, изменение состояния элементов и правильность их отображения после изменения данных. React Testing Library предоставляет удобные методы для работы с подобными сценариями, что позволяет эффективно тестировать функциональность обновлений и реакцию интерфейса на изменения.
Обновление списка элементов может происходить по разным причинам:
React и React Testing Library позволяют легко тестировать эти сценарии. Важным моментом является правильная проверка изменений в DOM после обновления состояния компонента.
Допустим, имеется компонент TodoList, который отображает
список задач. Каждая задача может быть добавлена или удалена с помощью
кнопок. Основная цель тестирования — убедиться, что при добавлении или
удалении задачи компонент корректно обновляет DOM.
import React, { useState } from 'react';
const TodoList = () => {
const [todos, setTodos] = useState([]);
const [newTodo, setNewTodo] = useState('');
const addTodo = () => {
if (newTodo) {
setTodos([...todos, newTodo]);
setNewTodo('');
}
};
const removeTodo = (todoToRemove) => {
setTodos(todos.filter(todo => todo !== todoToRemove));
};
return (
<div>
<input
type="text"
value={newTodo}
onCha nge={(e) => setNewTodo(e.target.value)}
/>
<button onCl ick={addTodo}>Добавить</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>
{todo}
<button onCl ick={() => removeTodo(todo)}>Удалить</button>
</li>
))}
</ul>
</div>
);
};
export default TodoList;
Для того чтобы протестировать добавление нового элемента в список, нужно выполнить несколько действий:
import { render, screen, fireEvent } from '@testing-library/react';
import TodoList from './TodoList';
test('добавление нового элемента в список', () => {
render(<TodoList />);
// Вводим текст в поле
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'Новая задача' } });
// Нажимаем на кнопку добавления
fireEvent.click(screen.getByText(/добавить/i));
// Проверяем, что новый элемент появился в списке
expect(screen.getByText('Новая задача')).toBeInTheDocument();
});
В данном примере используется метод fireEvent.change для
имитации ввода текста в поле и fireEvent.click для клика по
кнопке добавления задачи. После выполнения этих действий проверяется,
что новый элемент появился в списке с помощью expect.
Для проверки удаления элемента из списка необходимо:
test('удаление элемента из списка', () => {
render(<TodoList />);
// Добавляем два элемента
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'Задача 1' } });
fireEvent.click(screen.getByText(/добавить/i));
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'Задача 2' } });
fireEvent.click(screen.getByText(/добавить/i));
// Находим кнопку удаления для второго элемента и нажимаем её
const deleteButton = screen.getAllByText(/удалить/i)[1];
fireEvent.click(deleteButton);
// Проверяем, что второй элемент исчез
expect(screen.queryByText('Задача 2')).not.toBeInTheDocument();
});
В данном тесте сначала добавляются два элемента, затем выполняется
клик по кнопке “Удалить” для второго элемента. Используется
screen.queryByText, чтобы убедиться, что второй элемент
больше не присутствует в DOM. Метод queryByText возвращает
null, если элемент не найден, что удобно для проверки его
исчезновения.
Часто список может обновляться асинхронно, например, после получения
данных с сервера. В таких случаях необходимо учитывать ожидание
обновлений с помощью await и методов асинхронного ожидания
из React Testing Library, таких как findByText.
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import TodoList from './TodoList';
test('асинхронное обновление списка после загрузки данных с сервера', async () => {
render(<TodoList />);
// Имитируем задержку для загрузки данных
jest.useFakeTimers();
setTimeout(() => {
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'Задача 3' } });
fireEvent.click(screen.getByText(/добавить/i));
}, 1000);
// Ждем, пока задача появится в списке
await waitFor(() => screen.getByText('Задача 3'));
// Проверяем, что элемент был добавлен
expect(screen.getByText('Задача 3')).toBeInTheDocument();
});
Здесь используется setTimeout для имитации асинхронной
операции, а затем waitFor для ожидания появления нового
элемента в списке. Этот подход позволяет тестировать компоненты, которые
взаимодействуют с внешними API или используют асинхронные вызовы.
Еще один важный момент при тестировании — это проверка корректности обновлений данных в списке. Например, после того как пользователь изменяет данные задачи или меняется состояние компонента, нужно удостовериться, что изменения отображаются правильно.
test('изменение данных элемента в списке', () => {
render(<TodoList />);
// Добавляем элемент в список
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'Старая задача' } });
fireEvent.click(screen.getByText(/добавить/i));
// Проверяем, что элемент добавлен
expect(screen.getByText('Старая задача')).toBeInTheDocument();
// Меняем данные элемента
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'Новая задача' } });
fireEvent.click(screen.getByText(/добавить/i));
// Проверяем, что старый элемент исчез, а новый появился
expect(screen.queryByText('Старая задача')).not.toBeInTheDocument();
expect(screen.getByText('Новая задача')).toBeInTheDocument();
});
В данном тесте сначала добавляется задача с текстом “Старая задача”, затем текст задачи изменяется, и добавляется новый элемент. После этого проверяется, что старый элемент был заменён новым.
Правильное тестирование обновлений элементов в списке с использованием React Testing Library позволяет обеспечить надёжность и корректность функционала. Важно учитывать различные сценарии, такие как добавление, удаление, изменение данных элементов и асинхронные операции. Важно также тестировать, что изменения корректно отображаются в DOM, а React компонент обновляется как ожидается.