条件渲染元素测试失败求助:React组件测试问题排查
问题描述
我是应用测试领域的新手,目前遇到一个无法定位原因的测试错误,希望得到帮助。我需要测试点击按钮后元素是否会在屏幕上显示或隐藏。
Greeting组件
export default function Greeting() { const [changedText, setChangedText] = useState(false); function changeTextHandler() { setChangedText(true); } return ( <div> <h2>Hello World!</h2> {!changedText && <p>It's good to see you!</p>} {changedText && <p>Changed!</p>} <button onClick={changeTextHandler}>Change Text!</button> </div> ); }
失败的测试代码
describe("Greeting component", () => { test('renders "Changed!" if the button was clicked', () => { render(<Greeting />); const buttonElement = screen.getByRole("button"); userEvent.click(buttonElement); const outputElement = screen.getByText("Changed!"); expect(outputElement).toBeInTheDocument(); }); test('does not render "good to see you" if the button was clicked', () => { render(<Greeting />); const buttonElement = screen.getByRole("button"); userEvent.click(buttonElement); const outputElement = screen.queryByText("good to see you", { exact: false, }); expect(outputElement).toBeNull(); }); })
错误描述
Greeting component › renders "Changed!" if the button was clicked
无法找到包含文本“Changed!”的元素。这可能是因为文本被多个元素拆分,此时您可以提供一个函数作为文本匹配器以提高灵活性。
Greeting component › does not render "good to see you" if the button was clicked
expect(received).toBeNull() Received: <p>It's good to see you!</p>
Package.json
{ "name": "testes", "private": true, "version": "0.0.0", "type": "commonjs", "scripts": { "dev": "vite", "test": "jest", "build": "vite build", "preview": "vite preview" }, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@babel/core": "^7.21.4", "@babel/preset-env": "^7.21.4", "@babel/preset-react": "^7.18.6", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", "@vitejs/plugin-react": "^3.1.0", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "vite": "^4.2.0" } }
问题原因与修复方案
测试失败的核心原因是**@testing-library/user-event v14+ 版本中,交互操作(如click)是异步的**,原代码没有等待点击完成就执行断言,导致React状态还未更新,测试查询的是旧状态下的元素。
修复后的测试代码
import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import Greeting from './Greeting'; describe("Greeting component", () => { test('renders "Changed!" if the button was clicked', async () => { const user = userEvent.setup(); // v14+ 需先创建用户实例 render(<Greeting />); const buttonElement = screen.getByRole("button"); await user.click(buttonElement); // 等待点击操作完成 const outputElement = screen.getByText("Changed!"); expect(outputElement).toBeInTheDocument(); }); test('does not render "good to see you" if the button was clicked', async () => { const user = userEvent.setup(); render(<Greeting />); const buttonElement = screen.getByRole("button"); await user.click(buttonElement); // 等待状态更新完成 const outputElement = screen.queryByText("good to see you", { exact: false, }); expect(outputElement).toBeNull(); }); })
关键说明
- v14+版本的
@testing-library/user-event要求先调用userEvent.setup()创建用户实例,所有交互操作需通过该实例调用 - 交互操作是异步的,必须用
await等待完成,确保React状态更新后再执行元素查询和断言
内容的提问来源于stack exchange,提问作者Cláudio Vitor Dantas
相关产品推荐
相关产品推荐

