React Testing Library 中如何正确测试异步加载的数据?
我用 React Testing Library 测试一个组件,它在 useEffect 里通过 fetch 获取数据并更新状态。但测试时总是拿不到渲染后的数据,断言失败。是不是要加 await 或者用 waitFor?
这是我的组件代码:
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(<code>/api/users/${userId}</code>)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]);
if (!user) return <div>Loading...</div>;
return <div>{user.name}</div>;
}
测试里我 mock 了 fetch,但 screen.getByText 始终找不到 user.name,控制台显示还是 “Loading…”。该怎么写才对?
首先你得做这几步:
1. 确保正确 mock 了 fetch。要用 jest.spyOn 或者全局 mock,建议用 jest.spyOn 更灵活
2. 测试中必须等待组件完成更新。可以用 waitFor 配合 findBy 查询
3. 别忘了 cleanup 和正确设置测试环境
来看具体代码实现。先 mock fetch:
然后是测试用例写法。关键是用 async/await 和 waitFor:
这里有几个要点:
- getByText 是同步的,找不到会直接报错
- findByText 是异步的,会不断重试直到超时
- waitFor 可以包裹任何断言,内部会重试
有时候你可能还需要 mock 更复杂的 fetch 场景,比如错误情况:
如果测试还是很慢,可以调整 waitFor 的超时时间:
最后提醒下,如果你用 React 18,可能需要额外注意 concurrent rendering 的影响,但基本思路是一样的。测试异步组件就是三个关键点:正确 mock、适当等待、合理断言。
首先确保你的测试文件顶部引入了这些:
然后测试代码要这么写:
几个关键点:
1. 测试函数要用async声明
2. 用waitFor包裹最终的断言,它会自动重试直到超时
3. 别忘了await waitFor
我经常遇到这种问题,特别是刚用RTL的时候。有时候还会配合findByText使用,但waitFor更通用些。如果还不行,可能是你的mock没设置对,检查下fetch的mock实现。