Обработка ошибок и console

При написании тестов для React-приложений с использованием React Testing Library важной частью является корректная обработка ошибок. В отличие от традиционных методов тестирования, библиотека делает упор на пользовательское взаимодействие с компонентами, что влечет за собой необходимость уметь правильно управлять ошибками и логами. Это не только повышает стабильность тестов, но и помогает выявлять возможные проблемы на ранних этапах разработки.

Логирование ошибок в тестах

В тестах с React Testing Library часто необходимо убедиться, что приложение корректно обрабатывает ошибки. В большинстве случаев разработчики используют console.error, console.warn или другие методы для логирования ошибок, возникающих в процессе рендеринга компонентов или в результате взаимодействий с пользователем.

import { render, screen } from '@testing-library/react';

test('должен показывать ошибку, если компонент не может загрузиться', () => {
  const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
  
  render(<ComponentThatFails />);
  
  expect(consoleError).toHaveBeenCalledWith(expect.stringContaining('Error: Failed to load component'));
  
  consoleError.mockRestore();
});

В этом примере мы шпионем за вызовом console.error, чтобы проверить, вызывается ли ошибка при рендеринге компонента, который ожидаемо не загружается. Это подход позволяет отслеживать важные ошибки, не оставляя их незамеченными.

Ожидание и обработка ошибок

React Testing Library предоставляет методы для асинхронного тестирования компонентов. При взаимодействии с компонентами, которые могут генерировать ошибки или иметь асинхронную логику, важно учитывать их обработку.

Метод waitFor позволяет ожидать появления ошибок в процессе рендеринга или асинхронных действий. Например, если компонент должен показать ошибку после асинхронного запроса, можно написать тест, который будет ожидать, пока ошибка не отобразится на экране.

import { render, screen, waitFor } from '@testing-library/react';
import axios from 'axios';
import Component from './Component';

jest.mock('axios');

test('должен отобразить сообщение об ошибке при неудачном запросе', async () => {
  axios.get.mockRejectedValue(new Error('Network error'));

  render(<Component />);

  await waitFor(() => {
    expect(screen.getByText(/ошибка при загрузке данных/i)).toBeInTheDocument();
  });
});

Здесь мы использовали mockRejectedValue для имитации неудачного запроса через Axios. Важно, что waitFor позволяет нам подождать, пока ошибка не будет отловлена и отображена в компоненте. Это гарантирует, что тест пройдет только тогда, когда ошибка будет реально отображена.

Перехват ошибок с jest.spyOn

Использование jest.spyOn позволяет перехватывать вызовы методов, таких как console.error или console.warn. Этот метод полезен, если необходимо проверить, что определенная ошибка была правильно залогирована или вызвана в ходе работы тестируемого компонента.

test('должен вызывать console.error при ошибке компонента', () => {
  const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});

  render(<ComponentThatThrowsError />);

  expect(errorSpy).toHaveBeenCalled();

  errorSpy.mockRestore();
});

В этом примере тестируемый компонент генерирует ошибку при рендеринге. Мы перехватываем вызов console.error, чтобы удостовериться, что ошибка была действительно залогирована в консоли. После завершения теста мы восстанавливаем оригинальную реализацию console.error, чтобы избежать побочных эффектов в других тестах.

Обработка ошибок внутри компонентов

В React компоненты часто обрабатывают ошибки с помощью компонента ErrorBoundary. Этот компонент позволяет ловить ошибки в дочерних компонентах и отображать запасной UI, что важно для улучшения UX. В тестах React Testing Library нужно учитывать и этот случай.

import { render, screen } from '@testing-library/react';
import ErrorBoundary from './ErrorBoundary';
import ComponentThatThrowsError from './ComponentThatThrowsError';

test('ErrorBoundary должен ловить ошибку и отображать запасной UI', () => {
  render(
    <ErrorBoundary>
      <ComponentThatThrowsError />
    </ErrorBoundary>
  );

  expect(screen.getByText(/что-то пошло не так/i)).toBeInTheDocument();
});

В этом примере компонент ErrorBoundary перехватывает ошибку, генерируемую компонентом ComponentThatThrowsError, и отображает запасной UI. Тест проверяет, что в случае возникновения ошибки пользователь увидит соответствующее сообщение.

Логирование ошибок в асинхронных действиях

Иногда ошибки могут происходить в асинхронных действиях, таких как обработка API-запросов или взаимодействие с внешними сервисами. В таких случаях важно не только обработать ошибку, но и проверить, что она была правильно залогирована.

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import axios from 'axios';
import MyComponent from './MyComponent';

jest.mock('axios');

test('должен отобразить ошибку при сбое запроса', async () => {
  axios.get.mockRejectedValue(new Error('Request failed'));

  render(<MyComponent />);

  fireEvent.click(screen.getByText(/отправить запрос/i));

  await waitFor(() => {
    expect(screen.getByText(/ошибка запроса/i)).toBeInTheDocument();
  });
});

Здесь мы имитируем сбой HTTP-запроса с помощью mockRejectedValue, затем выполняем действия, которые запускают этот запрос, и проверяем, что ошибка корректно отображается на экране.

Рекомендации по логированию ошибок в тестах

  1. Не пренебрегать обработкой ошибок: Ошибки — это важная часть работы с компонентами, особенно в продакшн-коде. Обработка ошибок в тестах помогает повысить стабильность приложения.

  2. Использование jest.spyOn для перехвата ошибок: Это полезный инструмент для проверки, что ошибки были логированы в консоль, без необходимости изменять исходный код.

  3. Асинхронные ошибки: Для асинхронных операций важно использовать waitFor, чтобы дождаться, пока ошибки не отобразятся в компоненте, и только после этого проверять корректность работы.

  4. Проверка запасного UI с ErrorBoundary: Для компонентов, использующих обработку ошибок с ErrorBoundary, необходимо убедиться, что fallback-UI корректно отображается при сбоях в рендеринге.

  5. Чистка после тестов: Важно не забывать о том, чтобы восстанавливать любые шпионы и моки после завершения тестов, чтобы избежать влияния на другие тесты.

Включение обработки ошибок в тесты React-приложений способствует улучшению качества кода и повышению надежности приложения, обеспечивая пользователю более предсказуемое поведение интерфейса.