State Management

Devtools и тестирование

Пользователь жалуется: корзина обнулилась после применения промокода. Воспроизвести вручную не выходит. Разработчик открывает Redux DevTools, видит ленту action, отматывает состояние на шаг назад - и обнаруживает, что обработчик промокода случайно вернул пустой объект вместо обновлённой корзины. Без истории и time-travel этот баг искали бы часами по логам. Предсказуемое ядро состояния - чистый редьюсер, сериализуемые action - даёт две вещи разом: инструменты отладки и лёгкое тестирование.

  • Redux DevTools с лентой action и time-travel для поиска момента, где состояние пошло не так
  • Devtools-middleware Zustand, показывающий изменения стора в той же панели Redux DevTools
  • Визуализатор XState от Stately, рисующий машину состояний как наглядную диаграмму переходов
  • Юнит-тесты чистых редьюсеров: на вход состояние и action, на выходе сверяется новое состояние
  • Команды, тестирующие стор и машину состояний без рендера UI, потому что логика отделена от вида

Предварительные знания

  • Устройство Redux: action, чистый reducer и единый store
  • Чистая функция: один и тот же вход даёт один и тот же выход без побочных эффектов
  • Идея сериализуемого action: его можно записать, передать и воспроизвести
  • Ядро Redux

Redux DevTools и time-travel

Redux DevTools это расширение браузера, которое показывает поток состояния. Каждый диспатченный action попадает в ленту с типом и payload. Рядом видно текущее состояние store и diff, который внёс последний action. Главная возможность - time-travel: состояние можно отмотать на любой прошлый шаг и посмотреть, как приложение выглядело в тот момент.

Работает это потому, что ядро Redux предсказуемо. Состояние меняется только через action, а reducer - чистая функция. Значит, последовательность action полностью определяет состояние: повторив ту же ленту, всегда получаем тот же результат. DevTools хранят историю action и пересчитывают состояние для любого выбранного шага, отсюда и time-travel.

  • Лента action: тип и payload каждого изменения по порядку
  • Diff состояния: что именно изменилось после последнего action
  • Time-travel: переход к состоянию на любом прошлом шаге
  • Импорт и экспорт сессии: ленту action можно сохранить и воспроизвести у себя

Возможность отмотать и воспроизвести опирается на сериализуемость action. Если в action кладут несериализуемое (функцию, промис, инстанс класса), DevTools не смогут его сохранить и воспроизвести. Поэтому action держат как простые сериализуемые объекты.

Благодаря какому свойству Redux возможен time-travel в DevTools?

Devtools Zustand и визуализатор XState

Инструменты отладки не привязаны к Redux. Zustand подключается к той же панели Redux DevTools через devtools-middleware: стор оборачивают, и его изменения появляются в ленте с именами действий. Это даёт ту же историю и наблюдение за состоянием без перехода на Redux.

Третий аргумент set это имя действия в ленте DevTools: 'increment' появится в истории как подписанный шаг, а не безымянное изменение. Так стор Zustand получает наблюдаемость уровня Redux при своей минимальной обвязке.

Для машин состояний есть отдельный класс инструментов. Визуализатор XState от Stately рисует машину как диаграмму: состояния это узлы, переходы это стрелки с именами событий. Машину видно целиком - какие состояния есть, по какому событию идёт переход, какие переходы невозможны. Это превращает логику переходов из кода в наглядную карту.

  • Лента action (Redux, Zustand devtools) — Хронология изменений во времени: какой action когда сработал и как поменял состояние. Отвечает на вопрос что произошло и в каком порядке
  • Диаграмма машины (визуализатор XState) — Структурная карта логики: какие состояния возможны и по каким событиям между ними переходят. Отвечает на вопрос какие переходы вообще допустимы

Лента action и диаграмма машины дополняют друг друга. Лента показывает конкретную историю одного прогона во времени, диаграмма показывает всю структуру допустимых состояний и переходов сразу. Первое помогает в отладке инцидента, второе - в проектировании и обзоре логики.

Что показывает визуализатор XState от Stately в отличие от ленты action в Redux DevTools?

Тестирование чистого ядра

У предсказуемого ядра есть второе следствие после отладки - лёгкое тестирование. Чистый редьюсер это функция без побочных эффектов: на вход состояние и action, на выход новое состояние. Такую функцию тестируют напрямую, без рендера компонентов, без DOM и без моков. Тест просто вызывает редьюсер и сверяет результат.

Второй expect проверяет неизменяемость: исходное состояние не должно мутировать. Чистый редьюсер обязан вернуть новый объект, а не править before на месте. Это тестируется тем же вызовом, и обе гарантии - правильный результат и отсутствие мутации - проверяются за один прогон.

Стор Zustand тестируется похоже: вызвать действие через getState, затем сверить getState. Машину состояний XState тестируют, прогоняя события и проверяя итоговое состояние и допустимость переходов. Во всех трёх случаях логика отделена от представления, поэтому проверяется без UI. Это прямое преимущество того, что состояние живёт в чистых функциях.

Отделение логики состояния от представления это то, что делает тесты быстрыми и устойчивыми. Редьюсер, стор и машина проверяются как обычные функции, без хрупких тестов, дёргающих DOM. Предсказуемое ядро окупается дважды: в отладке через DevTools и в тестах через чистоту.

Почему чистый редьюсер тестируется без рендера компонентов и DOM?

Связь с другими темами

Этот урок про отладку и тесты. В основе лежит устройство Redux:

  • Ядро Redux — Чистый reducer и сериализуемые action это то, что делает возможными и DevTools, и простые юнит-тесты

Итог

  • Redux DevTools показывают ленту action, текущее состояние и позволяют отматывать его назад через time-travel
  • Devtools-middleware Zustand подключает стор к той же панели Redux DevTools, давая историю изменений
  • Визуализатор XState от Stately рисует машину состояний как диаграмму состояний и переходов
  • Чистый редьюсер тестируется напрямую: на вход состояние и action, на выходе сверяется ожидаемое состояние
  • Стор и машину состояний тестируют без рендера UI, потому что логика состояния отделена от представления
  • Предсказуемое ядро состояния даёт отладку и тестирование разом: это следствие чистоты, а не отдельная библиотека

Связанные уроки

  • sm-11-redux-core — Redux DevTools и тестирование чистых редьюсеров опираются на устройство Redux: action, reducer и единый store
Devtools и тестирование

0

1

Войти