Как тестируешь компоненты

Ответ

Для тестирования компонентов использую Jest + React Testing Library (RTL). Основные подходы:

  1. Рендеринг – проверяю, что компонент отображается без ошибок:
test('renders button', () => {
  render(<Button>Click</Button>);
  expect(screen.getByText('Click')).toBeInTheDocument();
});
  1. Поведение – тестирую обработчики событий и состояние:
test('calls onClick when clicked', () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick} />);
  fireEvent.click(screen.getByRole('button'));
  expect(handleClick).toHaveBeenCalled();
});
  1. Снимки (Snapshots) – для контроля неожиданных изменений в верстке.

  2. Интеграционные тесты – проверяю взаимодействие с другими компонентами/хуками.

Ключевые принципы:

  • Тестирую как пользователь (через DOM, а не внутреннее состояние)
  • Избегаю тестирования реализации
  • Использую data-testid только когда нет других вариантов
  • Мокирую только внешние зависимости (API и т.д.)

Ответ 18+ 🔞

А, тестирование, говоришь? Ну, слушай, я тебе сейчас так разложу, что ты офигеешь, но по-человечески.

Вот смотри, чтобы мои компоненты не вели себя как последние мудаки в продакшене, я их держу в ежовых рукавицах. Инструмент? Jest да React Testing Library (или RTL, для своих). Это как связка ключа и отмычки — без них нихуя не проверишь.

Как я это делаю? По полочкам, блядь:

  1. Рендеринг, ёпта. Самый базовый чекап — не разваливается ли эта хрень при первом же взгляде. Как бабушка у подъезда: «А живой ли ты вообще?».
test('renders button', () => {
  render(<Button>Click</Button>);
  expect(screen.getByText('Click')).toBeInTheDocument();
});

Всё, глянул — кнопка на месте. Уже хорошо. Не на месте? Ну, пидарас шерстяной, иди фикси.

  1. Поведение, ёбушки-воробушки. А теперь самое интересное — а работает ли оно? Кликнул — что-то произошло? Не кликнул — не произошло? Это ж магия, блядь, её проверять надо.
test('calls onClick when clicked', () => {
  const handleClick = jest.fn(); // Подставная крыса, мок, короче
  render(<Button onClick={handleClick} />);
  fireEvent.click(screen.getByRole('button')); // БАЦ кликнул!
  expect(handleClick).toHaveBeenCalled(); // А крыса-то запищала? Значит, работает!
});

Вот это уже тест с характером. Не запищала крыса — значит, хуйня, а не кнопка.

  1. Снимки (Snapshots). Это как фотография твоего кода в молодости. Запустил раз, он сфоткал разметку. Потом, через месяц, когда ты там что-то «улучшил», запускаешь снова — а он тебе: «Слушай, а тут у тебя волосы выпали и морщины появились, это ожидаемо?». Удобно, чтобы случайно не сломать то, что не трогал. Но без фанатизма, а то заебешься эти снапшоты апдейтить.

  2. Интеграционные тесты. Это когда ты проверяешь не одного отбитого солдата, а целый взвод — как компоненты друг с другом или с хуками общаются. Чтобы не вышло, что кнопка жмётся, а данные в пропердоленную дыру улетают.

А теперь, блядь, главные принципы, чтобы не быть мудаком в тестах:

  • Тестируй как пользователь, а не как долбоёб. Не лезь во внутренности компонента, не проверяй стейты и пропсы напрямую. Ты должен кликать по кнопкам, заполнять поля — как это делает живой человек. И смотреть, что в ДОМе поменялось. Всё.
  • Не тестируй реализацию, тестируй результат. Наплевать, как внутри функция называется. Важно, что после её вызова на экране появилась надпись «Успех». Иначе с каждым рефакторингом тесты будут сыпаться, и терпения ноль ебать.
  • data-testid — это как кричать «АУУУ, я здесь!» в лесу. Используй только в самом крайнем случае, когда по-человечески через текст или роль элемент не найти. Сначала getByRole, getByText, getByLabelText. Это твои лучшие друзья.
  • Моки — это зло, но иногда необходимое. Мокай только внешний мир, который от тебя не зависит: запросы к АПИ, модули для работы с датами, всякие сторонние либы. Свою логику мокать — это путь в никуда, чистая симуляция работы.

Вот и вся философия. Не усложняй, думай как юзер, и будет тебе счастье. А то некоторые такие тесты пишут, что сам чёрт ногу сломит, а толку — хуй с горы.