Enzyme — это инструмент для тестирования компонентов React, который предоставляет удобный API для работы с компонентами и их поведением. В процессе тестирования часто возникает необходимость в создании пользовательских селекторов для более точного и гибкого взаимодействия с компонентами. Создание пользовательских селекторов в Enzyme позволяет повысить читаемость и стабильность тестов, а также улучшить точность поиска элементов на странице.
Пользовательские селекторы — это функции или методы, которые
используются для поиска элементов в дереве компонента, основываясь на
кастомных логиках или правилах. Например, можно создавать селекторы,
которые находят элементы по нестандартным аттрибутам или выполняют
дополнительные проверки на основе состояния компонента. Это важно, когда
стандартных методов поиска, таких как find(), недостаточно
для выполнения задачи.
Перед тем как рассматривать создание пользовательских селекторов, полезно понимать основные методы поиска элементов, которые предоставляет Enzyme. Это базовые средства для навигации по компонентам.
find() — основной метод для поиска
элементов внутри компонента. Он позволяет находить элементы по
CSS-селекторам, классам, тэгам и аттрибутам.
wrapper.find('.my-class'); // Поиск элемента с классом 'my-class'filter() — фильтрует уже найденные
элементы по условию.
wrapper.find('button').filterWhere(node => node.text() === 'Click me');exists() — проверяет наличие
элемента в компоненте.
wrapper.find('.my-class').exists();text() — извлекает текст из
элемента.
wrapper.find('h1').text(); // Возвращает текст из элемента <h1>Для создания пользовательских селекторов можно комбинировать эти методы, добавляя более сложные условия поиска.
Рассмотрим пример компонента, который рендерит список товаров. Каждое
товарное предложение имеет уникальный аттрибут
data-product-id. Задача — создать селектор, который найдет
товар по ID.
import React from 'react';
const ProductList = ({ products }) => (
<ul>
{products.map(product => (
<li key={product.id} data-product-id={product.id}>
{product.name}
</li>
))}
</ul>
);
export default ProductList;
Для поиска товара по data-product-id можно создать
пользовательский селектор:
const findProductById = (wrapper, id) => {
return wrapper.find(`[data-product-id="${id}"]`);
};
Этот селектор будет искать элемент списка по аттрибуту
data-product-id, что позволяет более точно выбрать нужный
товар.
В случае, когда селектор должен учитывать состояние компонента,
например, скрытые или отключенные элементы, можно использовать метод
filterWhere, который позволяет фильтровать элементы на
основе определённых условий.
Предположим, что компонент отображает список товаров, где каждый товар может быть активирован или деактивирован (например, товары могут быть в статусе “доступен” или “недоступен”). Для поиска активных товаров можно использовать следующее решение:
const findAvailableProducts = (wrapper) => {
return wrapper.find('li').filterWhere(node => node.prop('disabled') !== true);
};
Здесь мы ищем все элементы <li> и фильтруем их по
пропу disabled. Таким образом, мы получаем только активные
товары.
matchesElementМетод matchesElement может быть полезен для более
точного определения, соответствует ли элемент определённому шаблону. Он
используется для проверки того, соответствует ли найденный элемент
переданному JSX-элементу. Создание такого селектора позволяет
использовать более сложные и детализированные условия для поиска.
Пример:
const findProductByName = (wrapper, name) => {
return wrapper.find('li').filterWhere(node => node.matchesElement(<li>{name}</li>));
};
Здесь мы ищем элемент <li>, текст в котором
соответствует имени товара.
Пользовательские селекторы можно легко интегрировать с другими
методами Enzyme, такими как simulate, setState
и другими, что даёт возможность более гибко манипулировать компонентами
и тестировать их взаимодействие.
Пример использования кастомного селектора в тесте с симуляцией клика:
it('should trigger the correct action on click', () => {
const wrapper = shallow(<ProductList products={products} />);
const productItem = findProductById(wrapper, 1); // Ищем товар по ID
productItem.simulate('click'); // Симулируем клик по найденному товару
});
В данном примере с помощью пользовательского селектора мы находим элемент по уникальному идентификатору и выполняем с ним действие, что позволяет более точно контролировать поведение компонента.
Селекторы должны быть универсальными. Постарайтесь создавать такие функции, которые можно будет переиспользовать для разных компонентов. Это уменьшит дублирование кода и упростит поддержку тестов.
Минимизируйте использование “жестких” значений. В случае, когда можно использовать динамическое значение или проп, предпочтительнее делать это, чтобы тесты не зависели от фиксированных значений.
Четкая структура селекторов. Применяйте имена и логики, которые интуитивно понятны другим разработчикам. Хорошо написанные селекторы облегчают поддержку тестов в будущем.
Использование тестовых аттрибутов. Селекторы,
основанные на кастомных аттрибутах (data-*), позволяют
четко разграничить тестовую логику и поведение компонента, а также
избежать зависимости от внешних стилей.
Создание эффективных пользовательских селекторов позволяет значительно улучшить читаемость тестов, повысить их стабильность и упростить поддержку в будущем.