【问题标题】:Testing custom hook and getting "Warning: An update to TestHook inside a test was not wrapped in act测试自定义钩子并获得“警告:测试中对 TestHook 的更新未包含在行为中
【发布时间】:2019-10-29 21:44:15
【问题描述】:

编辑:我找到了一个解决方案,来自 Kent C. Dodds 的 this video

只需将 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 在值或延迟更改时运行。

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

请帮忙!

【问题讨论】:

标签: reactjs unit-testing react-hooks react-hooks-testing-library


【解决方案1】:

将此行换成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');
});```

【讨论】:

    猜你喜欢
    • 2022-07-23
    • 1970-01-01
    • 2020-12-13
    • 2020-07-10
    • 2022-11-25
    • 1970-01-01
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    相关资源
    最近更新 更多