Тестовый рендерер

Импортирование

import TestRenderer from 'react-test-renderer'; // ES6
const TestRenderer = require('react-test-renderer'); // ES5 с помощью npm

Обзор

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

Пакет react-test-renderer облегчает получение снимка иерархии представления платформы (чем-то похожего на DOM-дерево), отрендеренного компонентом React DOM или React Native. При этом не используются ни браузер, ни jsdom.

Пример:

import TestRenderer from 'react-test-renderer';

function Link(props) {
  return <a href={props.page}>{props.children}</a>;
}

const testRenderer = TestRenderer.create(
  <Link page="https://www.facebook.com/">Facebook</Link>
);

console.log(testRenderer.toJSON());
// { type: 'a',
//   props: { href: 'https://www.facebook.com/' },
//   children: [ 'Facebook' ] }

Jest может автоматически сохранять в файл снимок копии дерева в виде JSON, а затем проверять в тестах, что в этом снимке ничего не изменилось с момента прошлого исполнения теста: узнать подробнее.

Также есть возможность искать в дереве конкретные узлы и проверять утверждения относительно них:

import TestRenderer from 'react-test-renderer';

function MyComponent() {
  return (
    <div>
      <SubComponent foo="bar" />
      <p className="my">Hello</p>
    </div>
  )
}

function SubComponent() {
  return (
    <p className="sub">Sub</p>
  );
}

const testRenderer = TestRenderer.create(<MyComponent />);
const testInstance = testRenderer.root;

expect(testInstance.findByType(SubComponent).props.foo).toBe('bar');
expect(testInstance.findByProps({className: "sub"}).children).toEqual(['Sub']);

TestRenderer

Методы и поля экземпляра TestRenderer

TestInstance

Справочник

TestRenderer.create()

TestRenderer.create(element, options);

Создаёт экземпляр TestRenderer для переданного React-элемента. И хотя реальный DOM не будет использоваться, дерево компонентов будет полностью отрендерено в памяти и его можно будет протестировать с помощью утверждений. Возвращает экземпляр TestRenderer

TestRenderer.act()

TestRenderer.act(callback);

Подобно вспомогательному методу act() из react-dom/test-utils, TestRenderer.act подготавливает компонент для проверки утверждений. Используйте эту версию act() для оборачивания TestRenderer.create и testRenderer.update.

import {create, act} from 'react-test-renderer';
import App from './app.js'; // Тестируемый компонент

// рендер компонента
let root; 
act(() => {
  root = create(<App value={1}/>)
});

// проверка утверждений
expect(root.toJSON()).toMatchSnapshot();

// обновление с некоторыми отличающимися пропсами
act(() => {
  root.update(<App value={2}/>);
})

// проверка утверждений
expect(root.toJSON()).toMatchSnapshot();

testRenderer.toJSON()

testRenderer.toJSON()

Возвращает объект, представляющий собой отрендеренное дерево. В дереве будут присутствовать только те узлы, которые специфичны для платформы (например, узлы <div> или <View>) и их пропсы. А вот компонентов, созданных разработчиками, в этом дереве не будет. Это очень удобно для тестирования с помощью снимков.

testRenderer.toTree()

testRenderer.toTree()

Возвращает объект, представляющий собой отрендеренное дерево. В отличие от toJSON() в отрендеренное дерево попадут и пользовательские компоненты. Скорее всего, этот метод вряд ли будет полезен, пока вы не захотите создать собственную библиотеку тестирования поверх TestRenderer.

testRenderer.update()

testRenderer.update(element)

Повторно рендерит находящееся в памяти дерево компонентов с учётом нового корневого элемента. По сути, это симуляция вызова React-обновления для корневого элемента. Если новый элемент имеет тот же тип и ключ, что и предыдущий, то дерево будет обновлено. Иначе, будет перемонтировано новое дерево.

testRenderer.unmount()

testRenderer.unmount()

Демонтирует дерево, находящееся в памяти. При этом запустятся необходимые события жизненного цикла.

testRenderer.getInstance()

testRenderer.getInstance()

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

testRenderer.root

testRenderer.root

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

testInstance.find()

testInstance.find(test)

Находит единственный вложенный тестовый экземпляр для которого test(testInstance) возвращает true. Метод test(testInstance) должен вернуть true ровно для одного тестового экземпляра, в противном случае будет сгенерирована ошибка.

testInstance.findByType()

testInstance.findByType(type)

Находит единственный вложенный тестовый экземпляр с указанным типом type. Метод findByType сгенерирует ошибку, если тестовых экземпляров с указанным type не найдено или найдено больше одного.

testInstance.findByProps()

testInstance.findByProps(props)

Находит единственный вложенный тестовый экземпляр с указанными пропсами props. Метод findByProps сгенерирует ошибку, если тестовых экземпляров с указанными пропсами не найдено или найдено больше одного.

testInstance.findAll()

testInstance.findAll(test)

Находит все вложенные тестовые экземпляры, для которых test(testInstance) возвращает true.

testInstance.findAllByType()

testInstance.findAllByType(type)

Находит все вложенные тестовые экземпляры с указанным типом type.

testInstance.findAllByProps()

testInstance.findAllByProps(props)

Находит все вложенные тестовые экземпляры c указанными пропсами props.

testInstance.instance

testInstance.instance

Экземпляр компонента, соответствующий его тестовому экземпляру. Свойство доступно только для классовых компонентов, т. к. функциональные компоненты не имеют экземпляров. Этот экземпляр компонента будет соответствовать значению this внутри данного компонента.

testInstance.type

testInstance.type

Тип компонента, соответствующий его тестовому экземпляру. Например, компонент <Button /> имеет тип Button.

testInstance.props

testInstance.props

Пропсы, соответствующие тестовому экземпляру. Например, у компонента <Button size="small" /> пропсами будут {size: "small"}.

testInstance.parent

testInstance.parent

Родительский тестовый экземпляр текущего тестового экземпляра.

testInstance.children

testInstance.children

Дочерние тестовые экземпляры текущего тестового экземпляра.

Используем тестовый рендерер

Можно передать функцию createNodeMock в TestRenderer.create как параметр для создания собственных фиктивных рефов. Функция createNodeMock принимает элемент и возвращает фиктивный реф-объект.

Это может быть полезно для тестирования компонентов, которые используют рефы.

import TestRenderer from 'react-test-renderer';

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.input = null;
  }
  componentDidMount() {
    this.input.focus();
  }
  render() {
    return <input type="text" ref={el => this.input = el} />
  }
}

let focused = false;
TestRenderer.create(
  <MyComponent />,
  {
    createNodeMock: (element) => {
      if (element.type === 'input') {
        // возвращаем фиктивную функцию "focus"
        return {
          focus: () => {
            focused = true;
          }
        };
      }
      return null;
    }
  }
);
expect(focused).toBe(true);