无法使用来自testing-library/react的React 18和renderHook测试自定义钩子

Ber*_*eli 5 reactjs react-testing-library react-hooks

我有一个自定义钩子,可以在挂载时进行 API 调用并处理状态(isLoading、isError、数据、重新获取);

钩子非常简单:

    const useFetch = (endpoint, options) => {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);
    const [isLoading, setIsLoading] = useState(true);
    const [trigger, setTrigger] = useState(true);

    const triggerSearch = () => {
        setTrigger(!trigger);
    };

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(
                    `${process.env.API_URL}${endpoint}`
                );
                const json = await response.json();
                setData(json);
                setIsLoading(false);
            } catch (error) {
                setError(error);
                setIsLoading(false);
            }
        };
        fetchData();
    }, [endpoint, trigger]);
    return {
        data,
        isLoading,
        error,
        triggerSearch,
    };
};
Run Code Online (Sandbox Code Playgroud)

当尝试测试钩子时,我使用 jest 和testing-library/react。

在react 18中,不再支持testing-library中的react-hooks,因此我无法使用renderHook中的awaitForNextUpdate,因为它不返回它。

相反,我们应该使用 act 和 waitFor - 我已经这样做并且测试通过了。

问题是我收到以下错误

警告:测试中对 TestComponent 的更新未包含在 act(...) 中。

When testing, code that causes React state updates should be wrapped into act(...):
Run Code Online (Sandbox Code Playgroud)
test("should make an API call on mount", async () => {
    const hook = renderHook(() => useFetch("/api"));

    await act(async () => {
        await waitFor(() => expect(fetch).toHaveBeenCalledTimes(1));
    });

    expect(fetch).toHaveBeenCalledTimes(1);

    expect(getAccessTokenSilently).toHaveBeenCalledTimes(1);

    expect(hook.result.current.data).toEqual({ message: "Test" });
    expect(hook.result.current.isLoading).toEqual(false);
    expect(hook.result.current.error).toEqual(null);
});
Run Code Online (Sandbox Code Playgroud)

有人可以指出我正确的方向吗?我尝试删除所有断言并仅调用 renderHook,这也会导致相同的错误。

Ber*_*eli 9

所以我解决这个问题的方法是在 async act 中包含调用 setState 函数的所有内容(包括 renderhook 的初始化,因为它通过 useEffect 调用 api):

  describe("useFetch", () => {
    test("should make a call to the API and return the message", async () => {
        let hook;
        await act(async () => {
            hook = renderHook(() => useFetch("/api"));
        });
        const { result } = hook;
        expect(fetch).toHaveBeenCalledTimes(1);
        expect(getAccessTokenSilently).toHaveBeenCalledTimes(1);
        expect(result.current.data).toEqual({ message: "Test" });
        expect(result.current.isLoading).toEqual(false);
        expect(result.current.error).toEqual(null);
    });
});
Run Code Online (Sandbox Code Playgroud)

哦,并确保你正在导入行为@testing-library/react