Обновление элементов в списке

Обновление элементов в списке

В 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;

Тестирование добавления элемента в список

Для того чтобы протестировать добавление нового элемента в список, нужно выполнить несколько действий:

  1. Написать тест, который симулирует ввод данных в поле и нажатие кнопки.
  2. Убедиться, что новый элемент появился в DOM.

Тест на добавление элемента

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.

Тестирование удаления элемента

Для проверки удаления элемента из списка необходимо:

  1. Отобразить начальный список.
  2. Удалить элемент.
  3. Проверить, что элемент исчез из DOM.

Тест на удаление элемента

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 компонент обновляется как ожидается.