React-hooks-testing-library: Testing custom hook and getting "Warning: An update to TestHook inside a test was not wrapped in act...

Created on 15 Jun 2019  路  1Comment  路  Source: testing-library/react-hooks-testing-library

I've implemented a simple custom hook in order to debounce a value update.

Here is the code:

function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]);

  return debouncedValue;
}

The client of this hook is something like this (very simplified):

function Search(props) {
  const [searchTerm, setSearchTerm] = useState('');
  const debouncedSearchTerm = useDebounce(searchTerm, 500);

  // doing something useful with debouncedSearchTerm....
  // ...
  // ...
}

So, I'm trying to test the hook with the code below:

import { renderHook, act } from 'react-hooks-testing-library';
import useDebounce from '../useDebounce';

jest.useFakeTimers();

it.only('should update value after specified delay', () => {
  const { result, rerender } = renderHook(
    ({ value, delay }) => useDebounce(value, delay),
    { initialProps: { value: '', delay: 500 } }
  );

  expect(result.current).toBe('');
  jest.advanceTimersByTime(510);
  expect(result.current).toBe('');

  rerender({ value: 'Hello World', delay: 500 });

  expect(result.current).toBe('');
  jest.advanceTimersByTime(498);
  expect(result.current).toBe('');
  jest.advanceTimersByTime(3);
  expect(result.current).toBe('Hello World');
});

Although, the test passes, I get the following warning:

console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:102

Warning: An update to TestHook 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 */        This ensures that you're testing the behavior the user would see in the browser. Learn more at https://fb.me/react-wrap-tests-with-act        in TestHook        in Suspense

I get that if I'm about to call a function in order to update the internal state of the hook (e.g. increment() of a useCounter hook), I have to do it in an act function, as the documentation instructs.

But, the useDebounce hook I've implemented changes state by an internal useEffect that runs whenever value or delay change.

How can I get rid of this warning? Is it something wrong with my code? Am I forgetting to add something in the test code?

Please help!

Most helpful comment

I found a solution, coming from this video from Kent C. Dodds.

Just wrap the jest.advanceTimersByTime calls in an act function.

So this:

jest.advanceTimersByTime(510);

becomes:

act(()=>jest.advanceTimersByTime(510));

>All comments

I found a solution, coming from this video from Kent C. Dodds.

Just wrap the jest.advanceTimersByTime calls in an act function.

So this:

jest.advanceTimersByTime(510);

becomes:

act(()=>jest.advanceTimersByTime(510));
Was this page helpful?
0 / 5 - 0 ratings

Related issues

matthieuh picture matthieuh  路  4Comments

DaveStein picture DaveStein  路  7Comments

samuherek picture samuherek  路  3Comments

ahnkee picture ahnkee  路  4Comments

lrojas94 picture lrojas94  路  3Comments