React Testing Library (RTL) и Enzyme — это два популярных инструмента для тестирования компонентов в React. В то время как Enzyme имеет долгую историю и остаётся широко используемым, React Testing Library набирает популярность благодаря своему подходу, ориентированному на поведение пользователя, и более простому API. Миграция с Enzyme на RTL требует внимательного подхода, особенно для крупных проектов. В этой статье рассматриваются ключевые различия между этими двумя библиотеками и шаги, необходимые для успешного перехода.
Enzyme и RTL имеют разные философии тестирования. Enzyme предоставляет API, которое позволяет тестировщику манипулировать компонентами и их внутренними состояниями напрямую. Это даёт возможность тестировать их изнутри, проверяя детали реализации, такие как состояние, методы и рендеринг.
В отличие от этого, React Testing Library фокусируется на тестировании компонентов с точки зрения пользователя. Вместо того чтобы проверять внутреннюю логику и структуру, RTL акцентирует внимание на том, как компоненты взаимодействуют с пользователем через DOM. Это делает тесты более надёжными, поскольку они приближены к реальной работе приложения.
Когда проект использует Enzyme, тесты часто содержат проверки, направленные на внутренние детали компонента, такие как состояние или методы жизненного цикла. В RTL такой подход не является правильным, поскольку библиотека стремится уменьшить зависимость от реализации и сосредоточиться на результатах взаимодействий с пользователем.
Замена методов рендеринга В Enzyme для
рендеринга компонентов используется метод shallow, который
позволяет тестировать компонент в изоляции, не затрагивая его дочерние
компоненты. В RTL вместо этого используется метод render из
библиотеки @testing-library/react, который рендерит
компонент целиком, включая все его дочерние компоненты. Важным моментом
является то, что тесты с использованием render работают не
с внутренними компонентами, а с результатом рендеринга, что делает их
более устойчивыми и гибкими.
Пример с Enzyme:
const wrapper = shallow(<MyComponent />);
expect(wrapper.find('button').text()).toBe('Click me');
Аналогичный тест с использованием RTL:
const { getByText } = render(<MyComponent />);
expect(getByText('Click me')).toBeInTheDocument();Работа с событиями В Enzyme для симуляции
событий используется метод simulate. Например, чтобы
симулировать клик по кнопке, код выглядел бы так:
wrapper.find('button').simulate('click');
В RTL же необходимо использовать утилиту fireEvent из
библиотеки @testing-library/react, чтобы имитировать
действия пользователя. Это позволяет получить более точное поведение
компонента в реальных условиях.
Пример с Enzyme:
wrapper.find('button').simulate('click');
expect(wrapper.state().clicked).toBe(true);
Аналогичный код с RTL:
const { getByText } = render(<MyComponent />);
fireEvent.click(getByText('Click me'));
expect(getByText('Clicked')).toBeInTheDocument();Проверка состояния компонентов В Enzyme очень
распространены тесты, которые проверяют состояние компонента с помощью
метода state(). Например:
expect(wrapper.state().isOpen).toBe(false);
В RTL такое тестирование не является лучшей практикой, поскольку цель библиотеки — взаимодействие с компонентом как с пользователем, а не внутренние состояния. В случае необходимости проверки изменённого состояния, лучше использовать доступ к рендеру и проверку DOM-элементов:
const { getByText } = render(<MyComponent />);
fireEvent.click(getByText('Toggle'));
expect(getByText('Opened')).toBeInTheDocument();Методы жизненного цикла Enzyme предлагает доступ
ко всем методам жизненного цикла компонента, включая
componentDidMount, componentDidUpdate и т. д.
В тестах на Enzyme часто проверяются вызовы этих методов.
В RTL же тестирование методов жизненного цикла не практикуется.
Вместо этого следует сосредоточиться на конечном результате. Например,
вместо того чтобы проверять, был ли вызван метод
componentDidMount, нужно проверить, отрендерился ли
компонент должным образом после монтирования.
При миграции на React Testing Library потребуется также заменить несколько утилит, используемых в Enzyme:
find() → getBy, queryBy В Enzyme
используется метод find(), чтобы найти элементы в
компоненте. В RTL аналогичные действия выполняются с помощью таких
методов, как getByText, getByRole,
getByTestId, queryByText и других.
Пример с Enzyme:
const button = wrapper.find('button');
Пример с RTL:
const button = getByText('Click me');setState() → событие или эффект В Enzyme можно
вручную изменить состояние компонента с помощью setState(),
чтобы проверить его поведение в ответ на изменение состояния. В RTL
такой подход не используется. Вместо этого необходимо симулировать
действия пользователя (клик, ввод текста) или проверять результат
изменений через DOM.
В Enzyme:
wrapper.setState({ isOpen: true });
expect(wrapper.find('.modal')).toHaveLength(1);
В RTL:
fireEvent.click(getByText('Open Modal'));
expect(getByText('Modal Content')).toBeInTheDocument();Одна из сильных сторон React Testing Library — это поддержка
асинхронных операций. В Enzyme асинхронные тесты могут быть сложными,
особенно если используются промисы или таймеры. В RTL тесты, связанные с
асинхронной загрузкой данных или изменением состояния, легко пишутся с
использованием утилит вроде waitFor, findBy* и
findByText.
Пример с Enzyme:
setTimeout(() => {
wrapper.update();
expect(wrapper.find('.message').text()).toBe('Hello');
}, 1000);
Пример с RTL:
const { findByText } = render(<AsyncComponent />);
expect(await findByText('Hello')).toBeInTheDocument();
Фокус на доступности React Testing Library
предоставляет методы для проверки доступности элементов в DOM, такие как
getByRole, что помогает создавать более доступные
приложения. Например, можно проверить, правильно ли объявлен элемент с
ролью кнопки:
const button = getByRole('button');Методы для асинхронного поиска RTL предоставляет
удобные методы для работы с асинхронными компонентами. Такие методы как
waitFor, findBy, и другие позволяют легко
ожидать появления элемента в DOM, что делает тесты более стабильными и
надёжными при работе с асинхронным рендерингом.
Миграция с Enzyme на React Testing Library может потребовать значительных изменений в структуре тестов, особенно в крупных проектах, где тесты сильно зависят от внутренних реализаций компонентов. Однако подход RTL, ориентированный на поведение пользователя, имеет несколько явных преимуществ: тесты становятся более надёжными и устойчивыми к изменениям реализации, что облегчает поддержку тестов и улучшает их предсказуемость.
Кроме того, React Testing Library предоставляет более современный и простое API, которое способствует написанию более чистых и устойчивых тестов.