You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React异步任务RTL测试报错:无法找到[data-testid='reload-button']元素

无法找到元素:[data-testid="reload-button"] - React Testing Library测试问题

我用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 05:27:58