I have the following component - "A toggle button":
// ToggleButton.tsx
export function ToggleButton() {
const [isEnabled, setIsEnabled] = React.useState(true);
return (
<button
onClick={onClick={() => setIsEnabled((prev) => !prev)}}
data-testid="toggle-button"
>
{isEnabled ? (
<span>Light Mode</span>
) : (
<span>Dark Mode</span>
)}
</button>
);
}
I have a simple test that checks that the button displays the correct text after each click:
it('toggles between light and dark mode when clicked', async () => {
render(<ToggleButton />);
// Initial state should be Light Mode
expect(screen.getByText('Light Mode')).toBeInTheDocument();
// Click the button
const button = screen.getByTestId('toggle-button');
await userEvent.click(button);
// Should now show Dark Mode
await waitFor(() => {
expect(screen.getByText('Dark Mode')).toBeInTheDocument();
});
// Click again
await userEvent.click(button);
// Should be back to Light Mode
await waitFor(() => {
expect(screen.getByText('Light Mode')).toBeInTheDocument();
});
});
I am getting a warning:
Warning: An update to ToggleButton inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
I see that I can wrap await user.click
in act
and the warning goes away, but I am wondering if that is the correct approach since as far as I understand userEvent.click
is already wrapped in act
by default.
I am wondering if I am not simply silencing the test this way and is there perhaps a way to adjust what I am testing for to solve this warning? Also it would be helpful to know what change in React 18.3 introduced this change.
Here is a stackblitz sandbox to reproduce the issue: .tsx,src%2Fcomponents%2F__tests__%2FToggleButton.test.tsx