act — это вспомогательный механизм из React,
предназначенный для корректной обработки обновлений состояния и эффектов
в тестовой среде. Его основная задача — гарантировать, что все изменения
состояния, вызванные пользовательскими действиями, асинхронными
операциями или жизненным циклом компонентов, будут полностью применены
до момента выполнения проверок.
В контексте React Testing Library act играет ключевую
роль при тестировании хуков и компонентов, зависящих от обновления
состояния. Без него тесты могут становиться нестабильными, выдавать
предупреждения или работать некорректно из-за незавершённых
обновлений.
actReact использует пакетную обработку обновлений состояния. Это
означает, что вызовы setState, обновления через
useState, useReducer или побочные эффекты
(useEffect) не всегда выполняются синхронно. В обычном
приложении React сам управляет очередью обновлений, но в тестах эта
очередь должна быть явно завершена.
act создаёт специальный контекст, внутри которого
React:
act.Только после этого результаты можно считать стабильными и пригодными для проверок.
act с хукамиПри тестировании хуков напрямую (например, через
renderHook) любое изменение состояния должно быть обёрнуто
в act.
import { renderHook, act } from '@testing-library/react';
test('обновление состояния useState', () => {
const { result } = renderHook(() => {
const [count, setCount] = React.useState(0);
return { count, setCount };
});
act(() => {
result.current.setCount(1);
});
expect(result.current.count).toBe(1);
});
Ключевые моменты:
act;act;act
и обновления хуковХуки часто используют асинхронные операции: таймеры, промисы, запросы
данных. Для таких случаев применяется асинхронная версия
act.
test('асинхронное обновление состояния', async () => {
const { result } = renderHook(() => {
const [value, setValue] = React.useState(null);
React.useEffect(() => {
Promise.resolve('data').then(setValue);
}, []);
return value;
});
await act(async () => {
await Promise.resolve();
});
expect(result.current).toBe('data');
});
Особенности асинхронного act:
act возвращает
Promise;await act(...) гарантирует завершение всех асинхронных
эффектов;useEffect и связанных
обновлений.Типичное сообщение:
Warning: An update to ComponentName inside a test was not wrapped in act(...)
Это предупреждение означает, что React обнаружил обновление состояния вне контролируемого контекста. Причины:
setState вне act;Игнорирование предупреждения может привести к:
act и
пользовательских событийReact Testing Library стремится абстрагировать act от
разработчика. Большинство утилит уже используют его внутри себя.
Пример:
fireEvent.click(button);
или
await userEvent.click(button);
В этих случаях act вызывается автоматически. Однако это
работает только для событий, инициированных через API библиотеки. Любая
ручная логика, влияющая на состояние, по-прежнему требует явного
act.
act и таймерыПри использовании таймеров (setTimeout,
setInterval) необходимо сочетать act с
управлением временем.
jest.useFakeTimers();
test('обновление после таймера', () => {
const { result } = renderHook(() => {
const [ready, setReady] = React.useState(false);
React.useEffect(() => {
setTimeout(() => setReady(true), 1000);
}, []);
return ready;
});
act(() => {
jest.runAllTimers();
});
expect(result.current).toBe(true);
});
Важно:
act;actReact допускает цепочки обновлений, когда одно изменение состояния
вызывает другое. act корректно обрабатывает такие
сценарии.
act(() => {
result.current.increment();
result.current.increment();
});
Все изменения будут объединены в один стабильный результат. Это соответствует поведению React в реальном приложении.
act от
waitForwaitFor используется для ожидания определённого
состояния, а не для инициирования обновлений.
act — управляет процессом
обновленияwaitFor — ожидает результат
обновленияЧасто они используются совместно, но не взаимозаменяемы.
waitFor не заменяет необходимость оборачивать обновления в
act.
Распространённые проблемы:
act только вокруг ассертов;act автоматически выполнит асинхронную
логику без await;render вместо логики, вызывающей
обновления.Корректный подход:
render выполняется отдельно;act оборачивает только действия, меняющие
состояние;act.В React 18 усилилась автоматическая пакетная обработка обновлений, но
требования к act остались. В строгом режиме
(StrictMode) эффекты могут вызываться дважды, что делает
корректное использование act особенно важным при
тестировании хуков с побочными эффектами.
act при тестировании хуковact — это не просто техническое требование, а инструмент
синхронизации тестов с внутренней моделью React. Он обеспечивает:
При тестировании hook-логики act становится
фундаментальным элементом, без которого невозможно получить надёжный и
предсказуемый результат.