Full DOM rendering: mount()

Enzyme предоставляет несколько методов рендеринга компонентов в тестах, каждый из которых имеет свои особенности и применимость в зависимости от ситуации. Метод mount() является самым мощным инструментом для полного рендеринга компонента, создавая реальную среду, в которой компонент взаимодействует со всем DOM-деревом. Это позволяет тестировать компонент в его полной функциональности, включая жизненный цикл, обработку событий и взаимодействие с дочерними компонентами.

Что такое mount()?

Метод mount() выполняет рендеринг компонента в полноценном DOM. В отличие от метода shallow(), который рендерит только сам компонент без учета его дочерних компонентов, mount() создает реальный DOM-узел, в котором рендерится вся иерархия компонентов. Это особенно полезно для сложных компонентов, которые требуют рендеринга дочерних элементов и взаимодействия с ними.

import { mount } from 'enzyme';
import MyComponent from './MyComponent';

describe('<MyComponent />', () => {
  it('should render correctly with full DOM', () => {
    const wrapper = mount(<MyComponent />);
    expect(wrapper.find('.my-class').length).toBe(1);
  });
});

В приведенном примере компонент MyComponent рендерится с использованием mount(), и тест проверяет, что в его разметке присутствует элемент с классом .my-class.

Преимущества использования mount()

  • Тестирование жизненного цикла компонента: mount() позволяет протестировать все этапы жизненного цикла компонента, включая componentDidMount, componentDidUpdate и componentWillUnmount. Это важно для компонентов, которые требуют сложной логики на этих этапах.

  • Рендеринг дочерних компонентов: В отличие от shallow(), который рендерит только сам компонент, mount() позволяет отрисовывать все дочерние компоненты. Это необходимо, когда требуется проверить взаимодействие между родительским и дочерним компонентами.

  • Интерактивность: Метод mount() поддерживает обработку событий и позволяет тестировать взаимодействия с элементами, такие как клики, изменения значений в формах и т. д. Это дает возможность более полно тестировать компоненты с состоянием и пользовательским вводом.

Недостатки метода mount()

  • Медленная производительность: Поскольку mount() создает реальный DOM, его использование может быть медленным, особенно в крупных приложениях. Для простых тестов, где не требуется полного рендеринга, лучше использовать shallow().

  • Необходимость в реальном окружении: Для корректной работы mount() необходим реальный DOM, что делает его использование невозможным в средах без него, например, в некоторых мобильных приложениях или серверных рендеринг-сценариях.

Использование метода mount() в тестах

Рендеринг компонента с состоянием

mount() идеально подходит для тестирования компонентов, которые используют состояние. Он позволяет проверить, как изменение состояния влияет на вывод компонента, и взаимодействует ли компонент с дочерними элементами.

import { mount } from 'enzyme';
import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <button className="increment" onCl ick={() => setCount(count + 1)}>
        Increment
      </button>
      <p className="count">{count}</p>
    </div>
  );
};

describe('<Counter />', () => {
  it('should update count on button click', () => {
    const wrapper = mount(<Counter />);
    wrapper.find('.increment').simulate('click');
    expect(wrapper.find('.count').text()).toBe('1');
  });
});

В этом примере, после того как пользователь кликает по кнопке, метод simulate('click') имитирует событие клика, а тест проверяет, что значение счётчика обновилось.

Тестирование взаимодействия с дочерними компонентами

mount() необходим для тестирования взаимодействия между родительским компонентом и его детьми. Если компонент передает данные через пропсы или использует коллбеки для управления состоянием, то необходимо использовать mount() для рендеринга всей иерархии.

import { mount } from 'enzyme';

const Child = ({ onClick }) => (
  <button className="child" onCl ick={onClick}>Click Me</button>
);

const Parent = () => {
  const handleClick = () => alert('Clicked!');
  
  return <Child onCl ick={handleClick} />;
};

describe('<Parent />', () => {
  it('should call the onClick prop in Child when clicked', () => {
    const wrapper = mount(<Parent />);
    wrapper.find('.child').simulate('click');
    // Тут можно добавить проверку вызова функции, например, с использованием spy
  });
});

Здесь рендерится компонент Parent, который передает функцию обратного вызова onClick дочернему компоненту Child. Метод simulate('click') имитирует событие клика и проверяет, что оно корректно обработано.

Симуляция событий

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

wrapper.find('input').simulate('change', { target: { value: 'new value' } });
expect(wrapper.find('input').props().value).toBe('new value');

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

Взаимодействие с асинхронным кодом

При использовании mount() можно тестировать асинхронные компоненты, например, компоненты, которые загружают данные с сервера или используют setTimeout/setInterval. В таком случае можно использовать async/await или done для асинхронных тестов.

import { mount } from 'enzyme';

describe('<AsyncComponent />', () => {
  it('should load data after async call', async () => {
    const wrapper = mount(<AsyncComponent />);
    await wrapper.instance().loadData();
    wrapper.update();
    expect(wrapper.find('.data').text()).toBe('Loaded data');
  });
});

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

Заключение

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