Повторное использование кода в тестах

В процессе написания тестов на React-компоненты с использованием Enzyme часто возникает ситуация, когда одни и те же операции повторяются в нескольких тестах: рендеринг компонентов с разными пропсами, настройка моков, поиск элементов, имитация событий. Для поддержания чистоты кода и повышения читаемости тестов критически важно выделять повторяющиеся части в отдельные функции или утилиты.


Абстрагирование рендеринга компонентов

Enzyme предоставляет три основных метода рендеринга: shallow, mount и render. Часто тесты нуждаются в одних и тех же настройках рендеринга, например, обёртка компонента в провайдер контекста или установка дефолтных пропсов.

Пример организации повторного рендеринга через фабрику:

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

const defaultProps = {
  title: 'Тестовый заголовок',
  visible: true,
};

export const renderShallow = (props = {}) => {
  return shallow(<MyComponent {...defaultProps} {...props} />);
};

export const renderMount = (props = {}) => {
  return mount(<MyComponent {...defaultProps} {...props} />);
};

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

it('должен отображать заголовок', () => {
  const wrapper = renderShallow({ title: 'Новый заголовок' });
  expect(wrapper.find('h1').text()).toBe('Новый заголовок');
});

Ключевой момент: собственные фабрики рендеринга повышают читаемость и облегчают модификацию дефолтного поведения компонентов во всех тестах сразу.


Вынесение поиска элементов

Поиск элементов с помощью .find() часто повторяется. Вынесение селекторов в отдельные функции делает тесты более декларативными и снижает риск ошибок при изменении структуры DOM:

export const findTitle = wrapper => wrapper.find('h1');
export const findButton = wrapper => wrapper.find('button.submit');

Использование:

it('кнопка должна быть кликабельной', () => {
  const wrapper = renderShallow();
  const button = findButton(wrapper);
  expect(button.prop('disabled')).toBe(false);
});

Преимущество: изменение селектора в одном месте сразу отражается во всех тестах, где используется соответствующая функция.


Обработка общих сценариев действий

Для имитации событий и проверки их последствий лучше создавать вспомогательные функции.

export const clickButton = wrapper => {
  wrapper.find('button.submit').simulate('click');
};

Применение:

it('вызывает обработчик при клике', () => {
  const onCl ick = jest.fn();
  const wrapper = renderShallow({ onClick });
  clickButton(wrapper);
  expect(onClick).toHaveBeenCalled();
});

Это снижает дублирование кода и делает тесты более читаемыми, особенно если действие включает несколько шагов (клик → изменение состояния → проверка DOM).


Использование фабрик пропсов

Часто тесты требуют разных комбинаций пропсов. Вынесение их в отдельные функции упрощает генерацию сценариев:

export const createProps = (overrides = {}) => ({
  title: 'Дефолтный заголовок',
  visible: true,
  onClick: jest.fn(),
  ...overrides,
});

Тест с разными набором пропсов:

it('не отображает компонент, если visible = false', () => {
  const wrapper = renderShallow(createProps({ visible: false }));
  expect(wrapper.isEmptyRender()).toBe(true);
});

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


Создание вспомогательных утилит для повторяющихся проверок

Если несколько тестов проверяют одинаковые условия, полезно вынести проверку в функцию:

export const expectTitle = (wrapper, text) => {
  expect(wrapper.find('h1').text()).toBe(text);
};

Применение:

it('должен отображать корректный заголовок', () => {
  const wrapper = renderShallow({ title: 'Тест' });
  expectTitle(wrapper, 'Тест');
});

Такой подход делает тесты краткими и выразительными, а логику проверки можно обновлять централизованно.


Организация вспомогательных файлов

Часто повторяющийся код помещают в отдельный каталог, например tests/utils:

tests/
  utils/
    renderers.js
    selectors.js
    actions.js
    propsFactory.js

Каждый файл содержит отдельный тип утилит:

  • renderers.js — функции для рендеринга компонентов;
  • selectors.js — функции поиска элементов в DOM;
  • actions.js — имитация событий;
  • propsFactory.js — фабрики пропсов для тестов.

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


Интеграция с Jest

Enzyme тесно интегрируется с Jest, что позволяет комбинировать фабрики, мок-функции и проверки:

it('вызывает функцию с правильными аргументами', () => {
  const onSub mit = jest.fn();
  const wrapper = renderMount(createProps({ onClick: onSubmit }));
  clickButton(wrapper);
  expect(onSubmit).toHaveBeenCalledWith(expect.objectContaining({ type: 'click' }));
});

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


Практические рекомендации

  • Выделять повторяющиеся части тестов в функции: рендеринг, поиск элементов, события, проверки.
  • Использовать фабрики пропсов для генерации вариативных сценариев.
  • Хранить утилиты в отдельных файлах, чтобы избежать «захламления» тестов и облегчить поддержку.
  • Делать тесты декларативными, чтобы они описывали поведение компонента, а не детали реализации действий.
  • Обновление одного места (селектора, фабрики или проверки) автоматически отражается во всех тестах, что минимизирует риск ошибок при рефакторинге.

Повторное использование кода в тестах повышает стабильность, скорость написания и сопровождения тестовой базы, делая её более масштабируемой и структурированной.