Утилиты для тестирования
Импортирование
import ReactTestUtils from 'react-dom/test-utils'; // ES6
var ReactTestUtils = require('react-dom/test-utils'); // ES5 с npm
Обзор
ReactTestUtils
позволяет легко тестировать React-компоненты в любом тестовом фреймворке на ваш выбор. В Facebook мы используем Jest для гладкого тестирования JavaScript-кода. Если хотите обучиться Jest, ознакомьтесь с руководством по React.
Примечание:
Мы рекомендуем использовать инструмент React Testing Library, который значительно облегчает написание тестов, имитируя поведение пользователей вашего приложения в браузере, и просто побуждает к хорошим практикам в тестировании.
В случае использования React ≤ 16, попробуйте воспользоваться библиотекой Enzyme, которая позволяет легко проверять, управлять, а также просматривать вывод React-компонентов.
act()
mockComponent()
isElement()
isElementOfType()
isDOMComponent()
isCompositeComponent()
isCompositeComponentWithType()
findAllInRenderedTree()
scryRenderedDOMComponentsWithClass()
findRenderedDOMComponentWithClass()
scryRenderedDOMComponentsWithTag()
findRenderedDOMComponentWithTag()
scryRenderedComponentsWithType()
findRenderedComponentWithType()
renderIntoDocument()
Simulate
Справочник
act()
Чтобы подготовить компонент для тестирования, оберните код с рендерингом и выполнением обновлений внутри функции act()
. Это сделает код теста для компонентов React более близким к тому, как он рендерится в браузере.
Примечание:
Если вы используете пакет
react-test-renderer
, то он также предоставляет функциюact
, которая работает аналогичным образом.
Допустим, у нас есть компонент Counter
:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: 0};
this.handleClick = this.handleClick.bind(this);
}
componentDidMount() {
document.title = `Вы нажали на кнопку ${this.state.count} раз`;
}
componentDidUpdate() {
document.title = `Вы нажали на кнопку ${this.state.count} раз`;
}
handleClick() {
this.setState(state => ({
count: state.count + 1,
}));
}
render() {
return (
<div>
<p>Вы нажали на кнопку {this.state.count} раз</p>
<button onClick={this.handleClick}>
Нажми на меня
</button>
</div>
);
}
}
Теперь напишем тест для этого примера:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { act } from 'react-dom/test-utils';import Counter from './Counter';
let container;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
container = null;
});
it('рендер и обновление счётчика', () => {
// Тестируем первый рендер и метод componentDidMount
act(() => { ReactDOM.createRoot(container).render(<Counter />); }); const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('Вы нажали на кнопку 0 раз');
expect(document.title).toBe('Вы нажали на кнопку 0 раз');
// Тестируем второй рендер и метод componentDidUpdate
act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); }); expect(label.textContent).toBe('Вы нажали на кнопку 1 раз');
expect(document.title).toBe('Вы нажали на кнопку 1 раз');
});
- Не забывайте, что отправка DOM-событий работает только если DOM-контейнер добавлен в
document
. Можно использовать вспомогательную библиотеку React Testing Library, чтобы уменьшить количество шаблонного кода. - В «рецептах» содержится больше примеров и деталей о том, как работает
act()
.
mockComponent()
mockComponent(
componentClass,
[mockTagName]
)
Передайте фиктивный модуль компонента этому методу, чтобы дополнить его полезными методами, которые позволяют использовать его в качестве фиктивного компонента React. Вместо того чтобы рендерить как обычно, компонент становится простым элементом <div>
(или другим тегом mockTagName
, если указан), содержащий любые предоставленные дочерние элементы.
Примечание:
API-метод
mockComponent()
объявлен устаревшим. Поэтому вместо него рекомендуется использоватьjest.mock()
.
isElement()
isElement(element)
Возвращает true
, если element
любой React-элемент.
isElementOfType()
isElementOfType(
element,
componentClass
)
Возвращает true
, если element
является элементом React, тип которого имеет тип React componentClass
.
isDOMComponent()
isDOMComponent(instance)
Возвращает true
, если instance
является DOM-компонентом (таким как <div>
или <span>
).
isCompositeComponent()
isCompositeComponent(instance)
Возвращает true
, если instance
является пользовательским компонентом, определённым как класс или функция.
isCompositeComponentWithType()
isCompositeComponentWithType(
instance,
componentClass
)
Возвращает true
, если instance
является компонентом, который имеет тип React componentClass
.
findAllInRenderedTree()
findAllInRenderedTree(
tree,
test
)
Находит все компоненты в дереве tree
, для которых test(component)
возвращает true
. Сам по себе он не так полезен, но используется как примитив для других тестовых утилит.
scryRenderedDOMComponentsWithClass()
scryRenderedDOMComponentsWithClass(
tree,
className
)
Находит все DOM-элементы компонентов в отображаемом дереве, которые являются DOM-компонентами с сопоставлением имён классов className
.
findRenderedDOMComponentWithClass()
findRenderedDOMComponentWithClass(
tree,
className
)
Работает как scryRenderedDOMComponentsWithClass()
, но ожидает, что найдётся ровно один результат, который и будет возвращён. Если ничего не будет найдено или найдётся больше одного результата, генерирует исключение.
scryRenderedDOMComponentsWithTag()
scryRenderedDOMComponentsWithTag(
tree,
tagName
)
Ищет все DOM-элементы компонентов в отображённом дереве, которые являются DOM-компонентами, и имя которых соответствует tagName
.
findRenderedDOMComponentWithTag()
findRenderedDOMComponentWithTag(
tree,
tagName
)
Также как scryRenderedDOMComponentsWithTag()
но ожидает, что найдётся ровно один результат, который и будет возвращён. Если ничего не будет найдено или найдётся больше одного результата, генерирует исключение.
scryRenderedComponentsWithType()
scryRenderedComponentsWithType(
tree,
componentClass
)
Находит все экземпляры компонента, тип которых равен componentClass
.
findRenderedComponentWithType()
findRenderedComponentWithType(
tree,
componentClass
)
Работает так же как scryRenderedComponentsWithType()
, но ожидает, что найдётся ровно один результат, который и будет возвращён. Если ничего не будет найдено или найдётся больше одного результата, генерирует исключение.
renderIntoDocument()
renderIntoDocument(element)
Отображает React-элемент в отдельно взятом DOM-узле документа. Этой функции нужен DOM. Это фактически эквивалентно:
const domContainer = document.createElement('div');
ReactDOM.createRoot(domContainer).render(element);
Примечание:
window
,window.document
иwindow.document.createElement
должны быть доступными перед тем как вы импортируетеReact
. В противном случае React будет думать что не может получить доступ к DOM и такие методы какsetState
не будут работать.
Другие утилиты
Simulate
Simulate.{eventName}(
element,
[eventData]
)
Симулировать отправку события сработавшего на DOM-узле с дополнительным объектом eventData
.
Simulate
имеет метод для каждого события, которое React может понимать.
Кликнуть на элемент
// <button ref={(node) => this.button = node}>...</button>
const node = this.button;
ReactTestUtils.Simulate.click(node);
Изменить значение в поле ввода, а затем эмулировать нажатие кнопки ENTER.
// <input ref={(node) => this.textInput = node} />
const node = this.textInput;
node.value = 'жираф';
ReactTestUtils.Simulate.change(node);
ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});
Примечание:
Вам нужно будет предоставить все свойства события, которое вы используете в своём компоненте (например, keyCode, which и т. д.), поскольку React не создаёт ничего из этого.