При написании тестов для 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, затем выполняем действия, которые
запускают этот запрос, и проверяем, что ошибка корректно отображается на
экране.
Не пренебрегать обработкой ошибок: Ошибки — это важная часть работы с компонентами, особенно в продакшн-коде. Обработка ошибок в тестах помогает повысить стабильность приложения.
Использование jest.spyOn для перехвата
ошибок: Это полезный инструмент для проверки, что ошибки были
логированы в консоль, без необходимости изменять исходный код.
Асинхронные ошибки: Для асинхронных операций
важно использовать waitFor, чтобы дождаться, пока ошибки не
отобразятся в компоненте, и только после этого проверять корректность
работы.
Проверка запасного UI с
ErrorBoundary: Для компонентов, использующих
обработку ошибок с ErrorBoundary, необходимо убедиться, что
fallback-UI корректно отображается при сбоях в рендеринге.
Чистка после тестов: Важно не забывать о том, чтобы восстанавливать любые шпионы и моки после завершения тестов, чтобы избежать влияния на другие тесты.
Включение обработки ошибок в тесты React-приложений способствует улучшению качества кода и повышению надежности приложения, обеспечивая пользователю более предсказуемое поведение интерфейса.