Проверка Error Boundaries

Error Boundaries — это механизм в React, позволяющий ловить ошибки в компонентах и предотвращать их распространение на весь компонентный дереве. Он помогает избежать поломки всей страницы из-за ошибки в одном из компонентов. Вместо того чтобы приложение крашилось, Error Boundary позволяет отображать пользовательский интерфейс с ошибкой или заглушку, информируя пользователя о проблемах.

В тестировании React-компонентов с использованием Enzyme, важной задачей является проверка работы Error Boundaries. Нужно убедиться, что при возникновении ошибки в дочернем компоненте, Error Boundary корректно перехватывает ошибку и обрабатывает её.

Структура 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 Boundaries в Enzyme можно разбить на несколько шагов:

  1. Создание компонента, генерирующего ошибку.
  2. Рендеринг компонента внутри Error Boundary.
  3. Проверка, что ошибка перехвачена и отобразился правильный UI.

1. Создание компонента, генерирующего ошибку

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

class BrokenComponent extends React.Component {
  render() {
    throw new Error('Ошибка в компоненте');
    return <div>Этот код никогда не выполнится</div>;
  }
}

Этот компонент выбрасывает ошибку при рендере, что позволяет протестировать поведение Error Boundary при её перехвате.

2. Рендеринг внутри 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.

3. Проверка перехвата ошибок

Когда ошибка выбрасывается в компоненте, 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 после того, как произошла ошибка в дочернем компоненте.

4. Проверка метода 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. После того как ошибка будет выброшена, мы проверяем, был ли вызван этот метод.

5. Проверка работы с асинхронными ошибками

Иногда ошибки могут возникать не синхронно, например, при загрузке данных с сервера. В таких случаях необходимо использовать методы для работы с асинхронным кодом, такие как 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 требует внимательного подхода к обработке ошибок. Для проверки корректности их работы важно:

  • Создавать компоненты, которые генерируют ошибки.
  • Монтировать их внутри Error Boundary.
  • Проверять, что ошибка была перехвачена и что соответствующий UI отображается.

Enzyme предоставляет необходимые инструменты для поверхностного и полного рендеринга компонентов, а также для проверки жизненных циклов и состояния компонентов, что делает его мощным инструментом для тестирования React-приложений.