При тестировании пользовательских интерфейсов одной из ключевых задач является проверка корректности работы приложения в ошибочных состояниях. Ошибки могут возникать по различным причинам: от сетевых проблем до неправильных данных, переданных в компонент. Правильное тестирование error состояний помогает убедиться, что приложение адекватно реагирует на такие ошибки, предоставляя пользователю понятные сообщения и исправляя возможные баги.
Для начала важно понять, как обрабатывать ошибки в компонентах React.
В большинстве случаев ошибки обрабатываются с помощью состояния (state)
компонента, которое может отражать успешность или неудачу операции.
Также часто для обработки ошибок используются компоненты типа
ErrorBoundary, которые перехватывают ошибки на уровне
компонентов.
Пример обработки ошибки через состояние:
import React, { useState, useEffect } from 'react';
const DataFetcher = () => {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
fetch('/api/data')
.then((response) => response.json())
.then((result) => setData(result))
.catch((err) => setError('Не удалось загрузить данные'));
}, []);
if (error) {
return <div role="alert">{error}</div>;
}
return data ? <div>{JSON.stringify(data)}</div> : <div>Загрузка...</div>;
};
В этом примере компонента DataFetcher использует
состояния для хранения как загруженных данных, так и возможных ошибок.
Если возникает ошибка при загрузке данных, отображается сообщение об
ошибке. Важно, что компонент использует роль alert для
сообщения об ошибке, что помогает с доступностью и улучшает
тестируемость компонента.
В React Testing Library можно использовать несколько подходов для тестирования error состояний компонентов. Ключевыми аспектами являются:
jest.mock для имитации ошибокДля имитации ошибок в тестах часто используется метод
jest.mock, который позволяет подменять реальные вызовы,
например, запросы к серверу, на заранее подготовленные ошибки.
Пример теста с имитацией ошибки при загрузке данных:
import { render, screen, waitFor } from '@testing-library/react';
import DataFetcher from './DataFetcher';
// Мокаем функцию fetch, чтобы она всегда выбрасывала ошибку
jest.mock('node-fetch', () => jest.fn(() => Promise.reject(new Error('Network error'))));
test('отображает сообщение об ошибке при неудачной загрузке данных', async () => {
render(<DataFetcher />);
await waitFor(() => screen.getByRole('alert'));
expect(screen.getByRole('alert')).toHaveTextContent('Не удалось загрузить данные');
});
В этом примере с помощью jest.mock мы подменяем
стандартный fetch на версию, которая всегда возвращает
ошибку. После рендера компонента мы ожидаем, что на экране появится
сообщение об ошибке.
Когда компоненты выполняют асинхронные операции, важно использовать
такие методы, как waitFor, чтобы дождаться завершения
асинхронной операции перед проверкой результатов.
Пример:
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import UserProfile from './UserProfile';
test('отображает ошибку при неудачной загрузке профиля', async () => {
render(<UserProfile />);
// Мокируем запрос, который возвращает ошибку
global.fetch = jest.fn().mockRejectedValueOnce(new Error('Ошибка при загрузке профиля'));
fireEvent.click(screen.getByText(/Загрузить профиль/i));
await waitFor(() => screen.getByRole('alert'));
expect(screen.getByRole('alert')).toHaveTextContent('Ошибка при загрузке профиля');
});
Здесь мы сначала мокируем ошибку с помощью
mockRejectedValueOnce, затем симулируем клик по кнопке,
инициирующей загрузку данных. После выполнения асинхронной операции с
помощью waitFor проверяется, что на экране появилось
сообщение об ошибке.
ErrorBoundaryЕсли в проекте используется компонент ErrorBoundary для
перехвата ошибок, то тестирование будет немного отличаться. Компонент
ErrorBoundary позволяет обрабатывать ошибки, возникающие в
дочерних компонентах.
Пример компонента ErrorBoundary:
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error('Error caught by ErrorBoundary:', error, info);
}
render() {
if (this.state.hasError) {
return <div role="alert">Что-то пошло не так</div>;
}
return this.props.children;
}
}
Для тестирования можно имитировать ошибку внутри дочернего компонента
и убедиться, что ErrorBoundary правильно обработает эту
ошибку.
Пример теста:
import { render, screen } from '@testing-library/react';
import ErrorBoundary from './ErrorBoundary';
test('показывает ошибку при возникновении ошибки в дочернем компоненте', () => {
const BrokenComponent = () => {
throw new Error('Ошибка в компоненте');
};
render(
<ErrorBoundary>
<BrokenComponent />
</ErrorBoundary>
);
expect(screen.getByRole('alert')).toHaveTextContent('Что-то пошло не так');
});
Этот тест проверяет, что когда в компоненте
BrokenComponent возникает ошибка, она перехватывается
ErrorBoundary, который отображает сообщение об ошибке.
Важным аспектом является проверка доступности сообщений об ошибках. В
React Testing Library можно использовать роль alert для
того, чтобы сообщения об ошибках были правильно восприняты
вспомогательными технологиями, такими как экранные читалки.
Пример с использованием роли alert:
test('сообщение об ошибке доступно для экранных читалок', () => {
render(<DataFetcher />);
// Симулируем ошибку
fireEvent.click(screen.getByText('Загрузить данные'));
expect(screen.getByRole('alert')).toHaveTextContent('Не удалось загрузить данные');
});
В этом тесте проверяется, что при возникновении ошибки компонент
выводит сообщение с ролью alert, что позволяет улучшить
доступность приложения для пользователей с особыми потребностями.
Тестирование error состояний в React с использованием React Testing
Library заключается в том, чтобы правильно симулировать ошибки,
проверять корректное отображение сообщений об ошибках и обеспечивать
доступность этих сообщений для всех пользователей. Важными инструментами
для этого являются jest.mock, асинхронные ожидания через
waitFor и использование правильных ролей для элементов
ошибок. Properly handling and testing error states ensures better
stability and user experience in real-world applications.