Тестові утиліти

Імпорт

import ReactTestUtils from 'react-dom/test-utils'; // ES6
var ReactTestUtils = require('react-dom/test-utils'); // ES5 з npm

Огляд

ReactTestUtils спрощують тестування React-компонентів в обраному вами фреймворку для тестування. У Facebook ми використовуємо Jest для безболісного JavaScript-тестування. Дізнайтеся, як розпочати роботу із Jest на сайті Jest React Tutorial.

Примітка:

Ми рекомендуємо використовувати React Testing Library, котра спроектована для заохочення написання тестів та використовує ваші компоненти так, як це роблять кінцеві користувачі.

Альтернативно, Airbnb випустила тестову утиліту, що називається Enzyme, котра легко дозволяє затверджувати, маніпулювати і переміщувати вихідні дані ваших React-компонентів.

Довідка

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';
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('може відображатися та оновлювати лічильник', () => {
  // Тестуємо перший render та componentDidMount
  act(() => {
    ReactDOM.render(<Counter />, container);
  });
  const button = container.querySelector('button');
  const label = container.querySelector('p');
  expect(label.textContent).toBe('Ви клікнули 0 разів');
  expect(document.title).toBe('Ви клікнули 0 разів');

  // Тестуємо другий render та componentDidUpdate
  act(() => {
    button.dispatchEvent(new MouseEvent('click', {bubbles: true}));
  });
  expect(label.textContent).toBe('Ви клікнули 1 разів');
  expect(document.title).toBe('Ви клікнули 1 разів');
});

Не забувайте, що диспетчеризація подій DOM працює тільки тоді, коли до document додано контейнер DOM. Ви можете використовувати допоміжний пакунок на кшталт react-testing-library, щоб скоротити шаблонний код.


mockComponent()

mockComponent(
  componentClass,
  [mockTagName]
)

Передайте mock-компонент в цей метод, щоб розширити його корисними методами, які дозволяють використовувати його в якості фіктивного React-компонента. Замість звичного рендеру компонент стане простим <div> (або іншим тегом, якщо надано mockTagName), що містить всіх наданих потомків.

Примітка:

mockComponent() — застарілий API. Ми рекомендуємо використовувати поверховий рендер або замість нього — 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.render(element, domContainer);

Примітка:

Вам потрібно, щоб 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 = 'giraffe';
ReactTestUtils.Simulate.change(node);
ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});

Примітка

Ви повинні надати будь-яку властивість події, що використовуєте у вашому компоненті (напр. keyCode, which, і т.д.), оскільки React не створює жодної з них для вас.