如何与useEffect / setState挂钩

时间:2019-07-12 15:44:52

标签: react-hooks-testing-library

我无法通过以下测试:

import { useEffect, useState } from "react";

export function useComponentResources(required) {
  const [componentResources, setComponentResources] = useState(null);

  useEffect(() => {
    if (required) {
      // api call
      setTimeout(() => setComponentResources({}), 100);
    }
  }, [required]);

  return componentResources;
}
import { renderHook } from "@testing-library/react-hooks";
import { useComponentResources } from "./component-resources.hook";

describe("component-resources.hook", () => {
  it("fetches resources when required", () => {
    //act
    const { result } = renderHook(() => useComponentResources(true));

    //assert
    expect(result.current).toEqual({});
  });
});

它不断失败:

expect(received).toEqual(expected)

Expected value to equal:
  {}
Received:
  null

Difference:

  Comparing two different types of values. Expected object but received null.

   7 |     const { result } = renderHook(() => useComponentResources(true));
   9 |     //assert
> 10 |     expect(result.current).toEqual({});
  11 |   });
  12 | });

我已经在codeandbox中创建了一个repro案例:

https://codesandbox.io/embed/priceless-browser-94ec2

1 个答案:

答案 0 :(得分:0)

renderHook不会等待您的setTimeout被解雇;它不知道您的组件有什么“副作用”。因此,当您的expect()运行时,当前值仍是其默认值-null

我们可以使用waitForNextUpdate返回的对象上的renderHook来强制测试等待钩子再次更新。 waitForNextUpdate是一个函数,它返回一个承诺,该承诺将在钩子再次更新后(例如setTimeout触发时)解决。

import { renderHook } from "@testing-library/react-hooks";
import { useComponentResources } from "./component-resources.hook";

describe("component-resources.hook", () => {
  it("fetches resources when required", async () => {
    const { result, waitForNextUpdate } = renderHook(() => useComponentResources(true));

    await waitForNextUpdate();

    expect(result.current).toEqual({});
  });
});