我写了一个简单的自定义钩子。它所做的只是通过 fetch 调用 api,将数据保存在一个状态中并返回该状态,以便组件可以使用它。
以下是
useTodos.js
的代码
import { useEffect, useState } from "react";
export function useTodos() {
const [todos, setTodos] = useState([{ a: 1 }]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos?_limit=1")
.then((response) => response.json())
.then((data) => setTodos(data));
}, []);
return todos;
}
以下是
useTodos.test.js
的代码
import { waitFor, renderHook } from "@testing-library/react";
import { useTodos } from "./useTodos";
test("fetch should return data", async () => {
const data = renderHook(() => useTodos());
console.log(data.result.current);
await waitFor(() => {
console.log(data.result.current);
});
});
我得到的 console.log 输出:
console.log
[ { a: 1 } ]
at Object.<anonymous> (src/useTodos.test.js:6:11)
console.log
[ { a: 1 } ]
at src/useTodos.test.js:8:13
我的理解是waitFor回调中的状态应该在调用API后显示结果,但我得到的是我在
[ { a: 1 } ]
中设置的initialStateuseState
。
我该如何纠正这个问题?
您的问题是您的
expect()
回调中没有断言语句(waitFor
)。在 waitFor
回调中,必须至少有一个断言正在等待 Promise 得到解决或拒绝。
在您的情况下,您的代码应如下所示:
import { waitFor, renderHook } from "@testing-library/react";
import { useTodos } from "./useTodos";
test("fetch should return data", async () => {
const { result } = renderHook(() => useTodos());
expect(result.current).toEqual([{ a: 1 }]) // your hook got executed and has the initial state of todos
await waitFor(() => {
// waiting to get resolve the current promise
expect(result.current).toEqual(//The array of objects you expect//)
});
});
在
waitFor
回调中,我们等待 result.current
的承诺得到解决。在 results.current
中是保存为承诺的自定义钩子的所有返回值。在您的情况下,results.current
是您的待办事项列表。通过代码行 expect(result.current)
,我们正在等待待办事项列表的更新。发生此更新是因为您的 useEffect 挂钩被执行,并且您使用 setTodos
函数更新了待办事项列表状态。此状态更新会触发自定义挂钩的重新渲染并返回我们正在等待的新待办事项列表。