Error Boundaries — это механизм в React, позволяющий ловить ошибки в компонентах и предотвращать их распространение на весь компонентный дереве. Он помогает избежать поломки всей страницы из-за ошибки в одном из компонентов. Вместо того чтобы приложение крашилось, Error Boundary позволяет отображать пользовательский интерфейс с ошибкой или заглушку, информируя пользователя о проблемах.
В тестировании React-компонентов с использованием Enzyme, важной задачей является проверка работы Error Boundaries. Нужно убедиться, что при возникновении ошибки в дочернем компоненте, Error Boundary корректно перехватывает ошибку и обрабатывает её.
Для начала стоит рассмотреть базовую структуру компонента Error
Boundary. Как правило, он реализуется с помощью класса, который
использует методы жизненного цикла
static getDerivedStateFromError и
componentDidCatch.
Пример компонента Error Boundary:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
console.log(error, info); // Логирование ошибки, или можно отправить её на сервер
}
render() {
if (this.state.hasError) {
return <h1>Что-то пошло не так.</h1>;
}
return this.props.children;
}
}
Тестирование Error Boundaries в Enzyme можно разбить на несколько шагов:
Для того чтобы протестировать поведение Error Boundary, необходимо создать компонент, который будет генерировать ошибку. Это поможет проверить, как Error Boundary реагирует на ошибки.
class BrokenComponent extends React.Component {
render() {
throw new Error('Ошибка в компоненте');
return <div>Этот код никогда не выполнится</div>;
}
}
Этот компонент выбрасывает ошибку при рендере, что позволяет протестировать поведение Error Boundary при её перехвате.
Для того чтобы протестировать перехват ошибки, нужно «обернуть» наш
компонент с ошибкой в Error Boundary. Для этого можно использовать метод
shallow или mount из Enzyme.
Метод shallow позволяет провести поверхностный рендеринг
компонента, без рендеринга дочерних компонентов, тогда как
mount выполняет полный рендеринг всех дочерних компонентов,
включая их жизненные циклы.
Пример теста с использованием mount:
import { mount } from 'enzyme';
describe('ErrorBoundary', () => {
it('должен перехватывать ошибки и отображать сообщение об ошибке', () => {
const wrapper = mount(
<ErrorBoundary>
<BrokenComponent />
</ErrorBoundary>
);
expect(wrapper.text()).toBe('Что-то пошло не так.');
});
});
В данном тесте мы монтируем компонент Error Boundary с вложенным в него компонентом, который выбрасывает ошибку. Ожидаем, что текст на экране будет равен “Что-то пошло не так.”, что соответствует поведению Error Boundary.
Когда ошибка выбрасывается в компоненте, Error Boundary должен поймать её и обновить состояние. Важно проверить, что состояние компонента Error Boundary действительно изменяется, а сам компонент корректно перехватывает ошибку.
import { mount } from 'enzyme';
describe('ErrorBoundary', () => {
it('должен обновлять состояние при возникновении ошибки', () => {
const wrapper = mount(
<ErrorBoundary>
<BrokenComponent />
</ErrorBoundary>
);
// Проверяем, что состояние ErrorBoundary изменилось
expect(wrapper.state('hasError')).toBe(true);
});
});
Этот тест проверяет, что состояние компонента hasError
меняется на true после того, как произошла ошибка в
дочернем компоненте.
componentDidCatchМетод componentDidCatch позволяет регистрировать
информацию об ошибке или отправлять её на сервер. Чтобы протестировать
его работу, можно использовать шпионы или мок-функции.
Пример теста с использованием шпиона:
import { mount } from 'enzyme';
describe('ErrorBoundary', () => {
it('должен вызывать componentDidCatch при возникновении ошибки', () => {
const spy = jest.spyOn(ErrorBoundary.prototype, 'componentDidCatch');
mount(
<ErrorBoundary>
<BrokenComponent />
</ErrorBoundary>
);
expect(spy).toHaveBeenCalled();
spy.mockRestore(); // Восстанавливаем оригинальную функцию
});
});
В этом тесте мы следим за вызовом метода
componentDidCatch с помощью шпиона jest.spyOn.
После того как ошибка будет выброшена, мы проверяем, был ли вызван этот
метод.
Иногда ошибки могут возникать не синхронно, например, при загрузке
данных с сервера. В таких случаях необходимо использовать методы для
работы с асинхронным кодом, такие как async/await.
Пример с асинхронной ошибкой:
import { mount } from 'enzyme';
describe('ErrorBoundary', () => {
it('должен перехватывать асинхронные ошибки', async () => {
const AsyncBrokenComponent = () => {
throw new Promise((_, reject) => reject('Асинхронная ошибка'));
};
const wrapper = mount(
<ErrorBoundary>
<AsyncBrokenComponent />
</ErrorBoundary>
);
await Promise.resolve(); // Ожидаем завершения всех асинхронных операций
expect(wrapper.text()).toBe('Что-то пошло не так.');
});
});
Этот тест проверяет, что Error Boundary может корректно работать с асинхронными ошибками.
Тестирование Error Boundaries с помощью Enzyme требует внимательного подхода к обработке ошибок. Для проверки корректности их работы важно:
Enzyme предоставляет необходимые инструменты для поверхностного и полного рендеринга компонентов, а также для проверки жизненных циклов и состояния компонентов, что делает его мощным инструментом для тестирования React-приложений.