Изучение props и state

Основы работы с props и state в React

В React компоненты строятся на основе двух ключевых концепций управления данными: props и state. Props (свойства) — это данные, передаваемые компоненту извне, которые нельзя изменять внутри самого компонента. State — это внутреннее состояние компонента, которое может меняться в процессе жизненного цикла и напрямую влияет на рендеринг. Тестирование этих аспектов с помощью Enzyme позволяет убедиться, что компоненты корректно реагируют на входные данные и изменение состояния.

Установка и подготовка 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() });

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

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-событий.
  • Проверка рендеринга после изменения state гарантирует синхронизацию визуального отображения с внутренним состоянием.

Тестирование 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 после события подтверждает корректную работу обработчиков.
  • Проверка текста или других элементов DOM демонстрирует правильное отображение на основе состояния.

Передача 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');
    });
  });
});

Суть:

  • Тестирование через различные props обеспечивает проверку компонентного поведения при любых внешних данных.
  • Методы hasClass и text помогают подтвердить визуальную корректность рендеринга.

Итоговые наблюдения по работе с Enzyme

  • shallow используется для изоляции компонента и проверки props/state без рендеринга дочерних компонентов.
  • mount обеспечивает полный рендеринг с доступом к жизненному циклу, полезно для тестирования componentDidMount и эффектов.
  • state() и setState() позволяют полностью контролировать внутреннее состояние компонентов.
  • props() и динамическое обновление props через wrapper.setProps() помогают проверять реакцию компонента на внешние изменения данных.
  • Симуляция событий (simulate) связывает теоретическое состояние с реальными действиями пользователя, подтверждая корректность логики и рендеринга.

Работа с props и state через Enzyme позволяет создавать детальные и надёжные тесты, которые охватывают как внутреннюю логику, так и визуальные аспекты компонентов.