Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing custom hook and getting "Warning: An update to TestHook inside a test was not wrapped in act... #97

Closed
ghost opened this issue Jun 15, 2019 · 1 comment

Comments

@ghost
Copy link

ghost commented Jun 15, 2019

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!

@ghost
Copy link
Author

ghost commented Jun 16, 2019

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));

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

0 participants