I’m using vitest and @testing-libarary/react. Both tests pass, but the 2nd one shows a warning to use act(). Clicking on the foo and bar buttons causes a react state update, but it seems only when triggering setBaz inside the timeout does it complain.
export function Foo() {
const [foo, setFoo] = useState('');
const [bar, setBar] = useState('');
const [baz, setBaz] = useState('');
useEffect(() => {
if (bar) setTimeout(() => setBaz('baz'), 5000);
}, [bar]);
return (
<>
<button onClick={() => setFoo('foo')}>Foo: {foo}</button>
<button onClick={() => setBar('bar')}>Bar: {bar}</button>
<div>Baz: {baz}</div>
</>
);
}
test('should work', async () => {
const user = userEvent.setup();
render(<Foo />);
const foo = screen.getByText(/Foo:/);
await user.click(foo);
expect(foo.innerHTML).toEqual('Foo: foo');
});
/*
Warning: An update to Foo inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
*/
test('should work', async () => {
vi.useFakeTimers({ shouldAdvanceTime: true });
const user = userEvent.setup();
render(<Foo />);
const bar = screen.getByText(/Bar:/);
await user.click(bar);
vi.advanceTimersByTime(5000);
await waitFor(() => {
const baz = screen.getByText(/Baz:/);
expect(baz.innerHTML).toEqual('Baz: baz');
});
});
If I wrap the advance advanceTimersByTime in act(() => vi.advanceTimersByTime(5000))
then that fixes the warning.