Students Save 30%! Learn & create with unlimited courses & creative assets Students Save 30%! Save Now
Advertisement
  1. Code
  2. React
Code

Тестирование компонентов в React с использованием Jest и Enzyme

by
Length:MediumLanguages:

Russian (Pусский) translation by Anna k.Ivanova (you can also view the original English article)

Это вторая часть серии «Тестирование компонентов в React». Если у вас есть предыдущий опыт работы с Jest, вы можете пропустить вперед и использовать код GitHub в качестве отправной точки.

В предыдущей статье мы рассмотрели основные принципы и идеи, лежащие в основе разработки, основанной на тестах. Мы также создали среду и инструменты, необходимые для запуска тестов в React. Набор инструментов включал в себя Jest, ReactTestUtils, Enzyme и react-test-renderer.

Затем мы написали пару тестов для демонстрационного приложения с использованием ReactTestUtils и обнаружили его недостатки по сравнению с более надежной библиотекой, такой как Enzyme.

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

Начало работы с API Enzyme

Enzyme.js - библиотека с открытым исходным кодом, поддерживаемая Airbnb, и это отличный ресурс для разработчиков React. Она использует API ReactTestUtils, но, в отличие от ReactTestUtils, Enzyme предлагает высокоуровневый API и простой в понимании синтаксис. Установите Enzyme, если вы еще этого не сделали.

API-интерфейс Enzyme экспортирует три типа параметров рендеринга:

  1. мелкий рендеринг
  2. полный DOM-рендеринг
  3. статический рендер

Мелкий рендеринг используется для визуализации отдельного компонента в изоляции. Дочерние компоненты не будут отображаться, и, следовательно, вы не сможете утверждать их поведение. Если вы собираетесь сосредоточиться на модульных тестах, вам это понравится. Вы можете мелко отобразить компонент следующим образом:

Полный рендеринг DOM создает виртуальный DOM компонента с помощью библиотеки jsdom. Вы можете воспользоваться этой функцией, заменив метод underow() на mount() в приведенном выше примере. Очевидным преимуществом является то, что вы также можете отображать дочерние компоненты. Если вы хотите проверить поведение компонента со своими дочерними элементами, вы должны использовать это.

Статический рендеринг используется для визуализации компонентов на статический HTML. Он реализован с использованием библиотеки под названием Cheerio, и вы можете больше узнать о ней в документации.

Пересмотр наших предыдущих тестов

Вот те тесты, которые мы написали в последнем уроке:

src/components/__tests__/ProductHeader.test.js

Первый тест проверяет, имеет ли компонент ProducerHeader тег <h2>, а второй обнаруживает, имеет ли он класс CSS с названием title. Код трудно читать и понимать.

Вот тесты, переписанные с использованием Enzyme.

src/components/__tests__/ProductHeader.test.js

Во-первых, я создал мелко-рендерный DOM компонента <ProductHeader /> с использованием small() и сохранил его в переменной. Затем я использовал метод .find(), чтобы найти узел с тегом 'h2'. Он запрашивает DOM, чтобы узнать, есть ли совпадение. Поскольку существует только один экземпляр элемента, можно смело предположить, что node.length будет равен 1.

Второй тест очень похож на первый. Метод hasClass('title') возвращает истину если текущий узел имеет prop className со значением 'title'. Мы можем проверить правдивость, используя toBeTruthy().

Запустите тесты, используя yarn test, и оба теста должны пройти.

Отлично сработано! Теперь пришло время реорганизовать код. Это важно с точки зрения тестера, потому что читаемые тесты легче поддерживать. В вышеприведенных тестах первые две строки идентичны для обоих тестов. Вы можете реорганизовать их с помощью функции beforeEach(). Как следует из названия, функция beforeEach вызывается один раз перед выполнением каждого spec в блоке описания.

Вы можете передать стрелочную функцию в  beforeEach().

src/components/__tests__/ProductHeader.test.js

Написание единичных тестов со Jest и Enzyme

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

Testing Components in React - ProductDetails component highlighted
Мы собираемся протестировать выделенный раздел.

Единичный тест попытается утвердить следующие предположения:

  • Компонент существует, и props передаются.
  • Отображаются props, такие как имя, описание и доступность продукта.
  • Сообщение об ошибке отображается, когда props пусты.

Вот основной код теста. Первый beforeEach() сохраняет данные продукта в переменной, а второй - компонент.

src/components/__tests__/ProductDetails.test.js

Первый тест прост:

Здесь мы используем метод props(), который удобен для получения props компонента.

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

Метод text() особенно полезен в этом случае для извлечения внутреннего текста элемента. Попробуйте написать ожидание для product.status() и посмотреть, проходят ли все тесты.

Для окончательного теста мы собираемся подключить компонент ProductDetails без каких-либо props. Затем мы будем искать класс с именем .product-error и проверять, содержит ли он текст «Извините, продукт не существует».

Вот и все. Мы успешно протестировали компонент <ProductDetails /> в изоляции. Тесты такого типа известны как единичные тесты.

Тестирование обратных вызовов с использованием заглушек и шпионов

Мы только что научились тестировать props. Но чтобы по-настоящему протестировать компонент в изоляции, вам также необходимо проверить функции обратного вызова. В этом разделе мы напишем тесты для компонента ProductList и создадим заглушки для функций обратного вызова. Вот предположения, которые нам нужно проверить.

Testing components in React - ProductList Component
  1. Количество перечисленных продуктов должно быть эквивалентно количеству объектов, которые компонент получает в качестве props.
  2. Нажатие на <a> должно вызвать функцию обратного вызова.

Давайте создадим функцию beforeEach(), которая заполняет данные мок-продуктов для наших тестов.

src/components/__tests__/ProductList.test.js

Теперь давайте смонтируем наш компонент в другом блоке beforeEach().

ProductList получает данные продукта через props. В дополнение к этому, он получает обратный вызов от родителя. Хотя вы можете написать тесты для функции обратного вызова родителя, это не самая лучшая идея, если ваша цель - придерживаться модульных тестов. Поскольку функция обратного вызова принадлежит родительскому компоненту, включение логики родителя затруднит выполнение тестов. Вместо этого мы создадим функцию заглушки.

Что такое заглушка?

stub - это фиктивная функция, которая претендует на роль другой функции. Это позволяет самостоятельно тестировать компонент без импорта родительских или дочерних компонентов. В приведенном выше примере мы создали функцию заглушки с именем handleProductClick вызвав jest.fn().

Теперь нам просто нужно найти все <a> элементы в DOM и имитировать щелчок на первом элементе <a>. После нажатия мы проверим, вызвано ли handleProductClick(). Если да, то справедливо сказать, что наша логика работает так, как ожидалось.

Enzyme позволяет легко имитировать действия пользователя, такие как клики, используя метод simulate(). handlerProductClick.mock.calls.length возвращает количество раз, когда вызывалась функция mock. Мы ожидаем, что оно будет равно 1.

Другой тест относительно прост. Вы можете использовать метод find() для извлечения всех элементов <a> в DOM. Количество элементов <a> должно быть равно длине массива productData, который мы создали ранее.

Тестирование состояния компонента, LifeCycleHook и метода

Затем мы проверим компонент ProductContainer. Он имеет состояние, хук жизненного цикла и метод класса. Вот утверждения, которые необходимо проверить:

  1. componentDidMount вызывается ровно один раз.
  2. Состояние компонента заполняется после монтирования компонентов.
  3. Метод handleProductClick() должен обновлять состояние, когда идентификатор продукта передается в качестве аргумента.

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

Вы можете отслеживать функцию следующим образом:

src/components/__tests__/ProductContainer.test.js

Первый параметр для jest.spyOn - это объект, который определяет прототип класса, за которым мы следим. Второй - это имя метода, который мы хотим шпионить.

Теперь визуализируйте компонент и создайте утверждение, чтобы проверить, был ли вызван шпион.

Чтобы проверить, что состояние компонента заполнено после монтирования компонента, мы можем использовать метод state() для Enzyme's, чтобы получить все в состоянии.

Третий немного сложнее. Нам нужно проверить, что handleProductClick работает должным образом. Если вы перейдете к коду, вы увидите, что метод handleProductClick() принимает идентификатор продукта в качестве входных данных, а затем обновляет this.state.selectedProduct с подробностями этого продукта.

Чтобы проверить это, нам нужно вызвать метод компонента, и вы действительно можете это сделать, вызвав компонент component.instance().handleProductClick(). Мы передадим образец идентификатора продукта. В приведенном ниже примере мы используем идентификатор первого продукта. Затем мы можем проверить, обновлено ли состояние, чтобы подтвердить, что утверждение верно. Вот весь код:

Мы написали 10 тестов, и если все будет хорошо, вот что вы должны увидеть:

Final output with tests passing

Заключение

Уф! Мы рассмотрели почти все, что вам нужно знать, чтобы начать писать тесты на React, используя Jest and Enzyme. Теперь может быть подходящее время, чтобы перейти на веб-сайт Enzyme, чтобы более глубоко изучить их API.

Что вы думаете о написании тестов в React? Я хотел бы услышать вас в комментариях.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.