props и state в ReactВ React компоненты строятся на основе двух ключевых концепций
управления данными: props и state.
Props (свойства) — это данные, передаваемые компоненту
извне, которые нельзя изменять внутри самого компонента.
State — это внутреннее состояние компонента, которое может
меняться в процессе жизненного цикла и напрямую влияет на рендеринг.
Тестирование этих аспектов с помощью Enzyme позволяет убедиться, что
компоненты корректно реагируют на входные данные и изменение
состояния.
Для работы с Enzyme необходимо установить следующие пакеты:
npm install --save-dev enzyme enzyme-adapter-react-16
или, если используется React 17/18:
npm install --save-dev enzyme enzyme-adapter-react-17
После установки необходимо настроить адаптер:
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
Enzyme предоставляет несколько способов рендеринга:
shallow, mount и render. Для
тестирования props чаще всего используют shallow
rendering, так как он изолирует компонент от его дочерних
компонентов.
Пример тестирования props:
import React from 'react';
import { shallow } from 'enzyme';
import Button from './Button';
describe('Button component', () => {
it('должен корректно принимать props', () => {
const wrapper = shallow(<Button label="Click me" disabled={true} />);
// Проверка значения prop
expect(wrapper.props().disabled).toBe(true);
expect(wrapper.props().label).toBeUndefined(); // label может быть в children
});
it('должен корректно рендерить текст из props', () => {
const wrapper = shallow(<Button label="Click me" />);
// Проверка текста внутри кнопки
expect(wrapper.text()).toBe('Click me');
});
});
Ключевые моменты:
wrapper.props() возвращает объект всех props верхнего
компонента.children, проверку необходимо
выполнять через wrapper.text().stateДля классовых компонентов state играет критическую роль
в логике взаимодействия. Enzyme позволяет напрямую получать и изменять
состояние с помощью методов state() и
setState().
Пример:
import React, { Component } from 'react';
import { shallow } from 'enzyme';
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return <div>{this.state.count}</div>;
}
}
describe('Counter component', () => {
it('начальное состояние count должно быть 0', () => {
const wrapper = shallow(<Counter />);
expect(wrapper.state('count')).toBe(0);
});
it('increment корректно увеличивает count', () => {
const wrapper = shallow(<Counter />);
wrapper.instance().increment();
expect(wrapper.state('count')).toBe(1);
});
it('рендеринг соответствует текущему state', () => {
const wrapper = shallow(<Counter />);
wrapper.setState({ count: 5 });
expect(wrapper.text()).toBe('5');
});
});
Особенности:
wrapper.state('ключ') возвращает текущее значение
конкретного состояния.wrapper.setState({ ключ: значение }) позволяет
имитировать изменения состояния без вызова UI-событий.props и state через событияНа практике состояние и props часто изменяются через взаимодействие
пользователя. Enzyme предоставляет методы simulate и
find для имитации событий.
Пример:
import React, { Component } from 'react';
import { shallow } from 'enzyme';
class Toggle extends Component {
state = { on: false };
toggle = () => this.setState({ on: !this.state.on });
render() {
return <button onCl ick={this.toggle}>{this.state.on ? 'ON' : 'OFF'}</button>;
}
}
describe('Toggle component', () => {
it('кнопка переключается при клике', () => {
const wrapper = shallow(<Toggle />);
const button = wrapper.find('button');
expect(wrapper.state('on')).toBe(false);
expect(button.text()).toBe('OFF');
button.simulate('click');
expect(wrapper.state('on')).toBe(true);
expect(button.text()).toBe('ON');
button.simulate('click');
expect(wrapper.state('on')).toBe(false);
expect(button.text()).toBe('OFF');
});
});
Важные моменты:
simulate('событие') имитирует пользовательское
действие.state после события подтверждает корректную
работу обработчиков.props для тестирования динамического поведенияИногда требуется протестировать компонент при разных значениях props:
import React from 'react';
import { shallow } from 'enzyme';
import Alert from './Alert';
describe('Alert component', () => {
it('корректно отображает разные типы alert', () => {
const types = ['success', 'error', 'warning'];
types.forEach(type => {
const wrapper = shallow(<Alert type={type} message="Test message" />);
expect(wrapper.hasClass(`alert-${type}`)).toBe(true);
expect(wrapper.text()).toContain('Test message');
});
});
});
Суть:
hasClass и text помогают
подтвердить визуальную корректность рендеринга.shallow используется для изоляции компонента и проверки
props/state без рендеринга дочерних компонентов.mount обеспечивает полный рендеринг с доступом к
жизненному циклу, полезно для тестирования
componentDidMount и эффектов.state() и setState() позволяют полностью
контролировать внутреннее состояние компонентов.props() и динамическое обновление props через
wrapper.setProps() помогают проверять реакцию компонента на
внешние изменения данных.simulate) связывает теоретическое
состояние с реальными действиями пользователя, подтверждая корректность
логики и рендеринга.Работа с props и state через Enzyme
позволяет создавать детальные и надёжные тесты, которые охватывают как
внутреннюю логику, так и визуальные аспекты компонентов.