Условные стили и классы

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

Основные подходы к проверке классов

В React часто используются условные классы для изменения внешнего вида компонента:

function Button({ isPrimary, isDisabled }) {
  return (
    <button className={`btn ${isPrimary ? 'btn-primary' : 'btn-secondary'} ${isDisabled ? 'disabled' : ''}`}>
      Click me
    </button>
  );
}

Enzyme позволяет проверить наличие этих классов с помощью методов hasClass и find:

import { shallow } from 'enzyme';

const wrapper = shallow(<Button isPrimary={true} isDisabled={false} />);
expect(wrapper.hasClass('btn')).toBe(true);
expect(wrapper.hasClass('btn-primary')).toBe(true);
expect(wrapper.hasClass('disabled')).toBe(false);

Ключевой момент: hasClass проверяет класс на корневом элементе, тогда как метод find позволяет искать вложенные элементы по селекторам и проводить проверку классов на них:

const wrapper = shallow(<Button isPrimary={false} isDisabled={true} />);
const button = wrapper.find('button');
expect(button.hasClass('btn-secondary')).toBe(true);
expect(button.hasClass('disabled')).toBe(true);

Использование условного рендеринга для стилей

Иногда классы добавляются через библиотеку classnames или напрямую через условные выражения:

import classNames from 'classnames';

function Alert({ type }) {
  const alertClass = classNames('alert', {
    'alert-success': type === 'success',
    'alert-error': type === 'error'
  });

  return <div className={alertClass}>Message</div>;
}

Тестирование таких компонентов требует проверки нескольких вариантов пропсов:

const wrapperSuccess = shallow(<Alert type="success" />);
expect(wrapperSuccess.hasClass('alert-success')).toBe(true);
expect(wrapperSuccess.hasClass('alert-error')).toBe(false);

const wrapperError = shallow(<Alert type="error" />);
expect(wrapperError.hasClass('alert-error')).toBe(true);
expect(wrapperError.hasClass('alert-success')).toBe(false);

Особенность: classnames объединяет классы динамически, поэтому важно проверять конкретные комбинации для различных условий.

Проверка стилей через prop('style')

В некоторых случаях стили передаются через inline-объекты:

function Box({ isHighlighted }) {
  return <div style={{ backgroundColor: isHighlighted ? 'yellow' : 'white' }}>Content</div>;
}

Enzyme позволяет получить объект стилей через метод prop:

const wrapper = shallow(<Box isHighlighted={true} />);
expect(wrapper.prop('style')).toHaveProperty('backgroundColor', 'yellow');

const wrapperNormal = shallow(<Box isHighlighted={false} />);
expect(wrapperNormal.prop('style')).toHaveProperty('backgroundColor', 'white');

Важно: Прямое сравнение объектов стилей может быть ненадёжным, если объект создаётся динамически. Использование toHaveProperty обеспечивает точечную проверку конкретного свойства.

Комбинированные проверки

Часто компоненты используют одновременно классы и inline-стили. Для таких случаев тесты могут комбинировать проверки hasClass и prop('style'):

function Card({ isSelected }) {
  return (
    <div
      className={`card ${isSelected ? 'selected' : ''}`}
      style={{ borderColor: isSelected ? 'blue' : 'gray' }}
    >
      Card Content
    </div>
  );
}

const wrapper = shallow(<Card isSelected={true} />);
expect(wrapper.hasClass('selected')).toBe(true);
expect(wrapper.prop('style')).toHaveProperty('borderColor', 'blue');

Проверка динамических классов в интерактивных компонентах

При тестировании событий, влияющих на классы, используют методы simulate и последующую проверку состояния:

class Toggle extends React.Component {
  state = { active: false };

  toggle = () => this.setState({ active: !this.state.active });

  render() {
    return <button className={this.state.active ? 'active' : ''} onCl ick={this.toggle}>Toggle</button>;
  }
}

const wrapper = shallow(<Toggle />);
const button = wrapper.find('button');

expect(button.hasClass('active')).toBe(false);
button.simulate('click');
expect(wrapper.find('button').hasClass('active')).toBe(true);

Вывод: Enzyme позволяет контролировать как статические, так и динамические классы и стили, используя комбинацию методов hasClass, prop, find и simulate. Такой подход обеспечивает полное покрытие условной логики отображения компонентов.

Советы по надежности тестов

  • Проверять классы на конкретном элементе через find, чтобы исключить случайные совпадения.
  • Использовать toHaveProperty для стилей вместо полного сравнения объектов.
  • Для компонентов с множеством условий писать отдельные тесты на каждую комбинацию пропсов или состояния.
  • Проверять динамическое изменение классов через simulate и последующую проверку состояния компонента.

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