3

编辑:我找到了一个解决方案,来自 Kent C. Dodds的这段视频。

只需将 jest.advanceTimersByTime 调用包装在一个 act 函数中。

所以这:

jest.advanceTimersByTime(510);

变成:

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

我已经实现了一个简单的自定义钩子,以消除值更新的抖动。

这是代码:

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

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

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

  return debouncedValue;
}

这个钩子的客户端是这样的(非常简化):

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

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

所以,我试图用下面的代码测试钩子:

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

虽然,测试通过,但我收到以下警告:

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.....       in TestHook        in Suspense

我知道,如果我要调用一个函数来更新钩子的内部状态(例如 useCounter 钩子的 increment()),我必须按照文档的指示在act函数中执行此操作。

但是,我实现的 useDebounce 钩子通过内部 useEffect 更改状态,该 useEffect 在值或延迟更改时运行。

我怎样才能摆脱这个警告?我的代码有问题吗?我是否忘记在测试代码中添加一些内容?

请帮忙!

4

1 回答 1

0

将此行包装成act

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('');
  // once delay time is passed, component is rerendered, so to capture that
  // in unit test, this line should be wrapped in act
  act(() => jest.advanceTimersByTime(3));
  expect(result.current).toBe('Hello World');
});```
于 2021-06-03T17:39:05.847 回答