React异步任务RTL测试报错:无法找到[data-testid='reload-button']元素
我用Create React App开发了一个简单项目,功能是通过网络请求获取用户列表并展示。为了避免请求真实服务器,编写RTL测试用例时mock了fetch调用并提供模拟数据,但遇到报错,提示找不到[data-testid="reload-button"]元素。
报错信息
无法找到元素:[data-testid="reload-button"] Ignored nodes: comments, script, style <body> <div /> </body> 15 | render(<Body />) 16 | > 17 | await waitFor(()=>expect(screen.getByTestId("reload-button"))) | ^ 18 | const usersArray = screen.getAllByTestId("users-list") 19 | expect(usersArray.length).toBe(5) 20 | }) at waitForWrapper (node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/wait-for.js:166:27) at Object.<anonymous> (src/components/__tests___/Body.test.js:17:18)
相关代码
Body组件(发起请求、管理状态)
//Body.js const Body = () => { const [ users, setUsers ] = useState([]) const [ reloadUsers , setReloadUsers] = useState(false) useEffect(() =>{ fetchUsers() },[reloadUsers]) const fetchUsers = async () => { const data = await fetch(`https://randomuser.me/api/?results=5`) const jsonData = await data.json() setUsers(jsonData?.results) } if(!users)return null return users.length===0 ? <p>Loading...</p> : ( <div> <button data-testid='reload-button' onClick={()=> setReloadUsers(prev => !prev) } > Load different users </button> <UserList users={users} /> </div> ) }
UserList组件(渲染用户列表)
//UserList.js const UserList = ({users}) => { const displayList = users.map(user=>( <li data-testid="users-list" style={{'display' : 'flex' , 'alignItems' : 'center' , 'margin' : '20px'}} key={user?.login?.uuid} > <img style={{'borderRadius':'30px' , 'marginRight' : '20px'}} src={user?.picture?.thumbnail} alt='thumbnail' /> <span>{user?.name?.first} {user?.name?.last} </span> </li> )) return ( <div> <h5>UserList</h5> <ul style={{ 'listStyleType' : 'none' }} > {displayList} </ul> </div> ) }
测试文件(Body.test.js)
//Body.test.js import { render, screen, waitFor } from "@testing-library/react" import Body from "../Body" import { usersList } from "../utils/constants"; test('user list should appear on screen', async ()=>{ global.fetch = jest.fn(()=>{ return Promise.resolve({ json : () => { return Promise.resolve(usersList) } }) }) render(<Body />) await waitFor(()=>expect(screen.getByTestId("reload-button"))) const usersArray = screen.getAllByTestId("users-list") expect(usersArray.length).toBe(5) })
问题原因及解决方法
1. Mock数据结构不匹配真实API
真实的randomuser.me API返回的是包含results字段的对象,而测试中直接返回了usersList数组。这会导致jsonData?.results拿到undefined,进而setUsers(undefined),触发组件中的if(!users)return null,页面渲染空div,自然找不到按钮。
解决:
修改mock的fetch返回结构,把usersList包裹在results字段中:
global.fetch = jest.fn(()=>{ return Promise.resolve({ json : () => { // 确保返回结构和真实API一致 return Promise.resolve({ results: usersList }) } }) })
2. waitFor中的断言不完整
waitFor里只写了expect(screen.getByTestId("reload-button")),这只是获取元素,没有实际断言条件,waitFor无法正确判断等待的结束时机。
解决:
补充完整断言,使用toBeInTheDocument():
await waitFor(()=>{ expect(screen.getByTestId("reload-button")).toBeInTheDocument() })
3. 可选优化:清理mock避免影响其他测试
测试结束后清除fetch的mock,防止污染其他测试用例:
afterEach(() => { jest.restoreAllMocks() })
内容的提问来源于stack exchange,提问作者JAY PRAKASH
相关产品推荐
相关产品推荐

