Как тестировать компоненты с отслеживанием состояния с помощью Jest и Enzyme

Если возможно, вам следует разделить логику с отслеживанием состояния и свое представление. Обычно это делается с помощью редукторов в стиле Redux и компонентов без сохранения состояния. Оба из них довольно легко протестировать и могут составить большую часть вашего приложения.

Однако иногда вы, вероятно, все же хотите протестировать компонент с отслеживанием состояния или просто не хотите проводить рефакторинг для использования редукторов. Все усложняется, особенно когда изменения состояния происходят асинхронно. В этой статье я расскажу, как можно протестировать различные кейсы компонентов с отслеживанием состояния, используя React 16, Jest и Enzyme.

Создание образца приложения

Начнем с создания образца приложения с помощью create-react-app.

npx create-react-app react16-testing

Теперь мы можем легко запускать тесты, запустив npm run test. После этого мы редактируем src/App.js и добавляем минимальный пример для наших целей тестирования. Мы создаем функциональный компонент, который использует хук useState.

Чтобы получить визуальную обратную связь, добавьте следующие строки в свой app.css.

.box { color: white; }
.blue { background-color: blue; }
.red { background-color: red; }
.green { background-color: green; }

Вышеупомянутое приложение будет просто отображать 3x button элемента и 1x div с background-color, в зависимости от того, какую кнопку вы нажали.

Установка тестовых зависимостей

Предположим, мы хотим проверить, отображает ли компонент правильный класс после нажатия кнопки. Для этого мы будем использовать shallow() API рендеринга от Enzyme. Вы можете установить связанные зависимости с помощью:

npm install --save enzyme enzyme-adapter-react-16 react-test-renderer

После этого вы должны создать ./src/setupTests.js с некоторыми начальными командами, которые должны выполняться до начала тестирования.

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });

До React 16 нам приходилось использовать компоненты класса, если мы хотели использовать состояние. В то время вы бы неглубоко отрисовали компонент, который хотите протестировать, и могли бы вызвать setState() непосредственно на этом компоненте, чтобы проверить, правильно ли ведет себя компонент при изменении состояния. С появлением хуков в функциональных компонентах это больше невозможно.

Тестирование функционального компонента с помощью крючков с использованием фермента

Однако вы все равно можете запустить соответствующее событие, которое изменяет состояние, вручную. Вот пример: App.test.js, который нажимает последнюю кнопку, чтобы вызвать изменение состояния и повторную визуализацию.

Часто вы хотите использовать событие по умолчанию для доступа к атрибутам данных, как показано в следующем примере, вместо того, чтобы напрямую связывать значения с функцией.

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

Тестирование функционального компонента в асинхронном состоянии

Теперь в реальном приложении изменения вашего состояния, вероятно, будут запускаться асинхронно. Если наше изменение состояния в handleClick происходит асинхронно, как в примере ниже, наш тест тоже не удастся.

function handleClick(e) {
    setTimeout(() => {
        changeColor(e.target.getAttribute('data-color'));
    }, 1000);
}

В этом примере состояние изменится через одну секунду, и тест завершится еще до того, как произойдет повторный рендеринг. Здесь мы могли бы вернуть Promise в handleClick, который разрешается после изменения состояния. В нашем App.test.js мы можем затем использовать async/await, чтобы дождаться изменения состояния. Для получения более подробной информации посетите jestjs async tutoria l.

function handleClick(e) {
    const node = e.target;
    return new Promise(resolve => {
        setTimeout(() => {
            changeColor(node.getAttribute('data-color'));
            resolve();
        }, 1000);
    });
}

Сделать компонент функции с сохранением состояния тестируемым

Итак, чтобы сделать функциональный компонент с перехватчиками тестируемым, функция, запускающая изменение состояния:

  • Должен быть доступен как опора, чтобы мы могли запускать его вручную
  • Требуется фиктивное событие, если оно использует значения из него
  • Должен возвращать Promise, если изменение состояния происходит асинхронно