React Testing Library下拉选项无法选中的问题排查
问题:React Testing Library测试原生Select组件无法选中选项
使用React Testing Library测试原生select下拉组件时,无论用userEvent.selectOptions还是fireEvent.select触发选择,都无法成功选中选项。断言目标option的selected属性始终返回false,fireEvent.select返回值为undefined而非true。尝试react-select-event库也无效,测试原生组件同样失败。
测试代码
userEvent版本
import React from "react"; import { fireEvent, render } from "@testing-library/react"; import selectEvent from "react-select-event"; import userEvent from "@testing-library/user-event"; test("Can Select Item", async () => { const user = userEvent.setup(); const screen = render( <select data-testid="test"> <option value="1" data-testid="Hey"> Hey </option> <option value="2">There</option> </select> ); await user.selectOptions(screen.getByTestId("test"), "Hey"); expect(screen.getByTestId("Hey").hasAttribute("selected")).toBeTruthy(); });
fireEvent版本
fireEvent.select(screen.getByTestId("test"), { target: { value: "1" } }); expect(screen.getByTestId("Hey").hasAttribute("selected")).toBeTruthy();
package.json配置
{ "name": "test-jest", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }
错误信息
SelectField Test > Can Select Item ----- Error: expect(received).toBeTruthy() Received: false Jest
环境版本
❯ nvm -v 1.1.11 ❯ npx -v 6.14.15 ❯ npm -v 6.14.15 ❯ node Welcome to Node.js v14.18.3.
解决方案
1. 遵循RTL测试理念:断言用户可见的结果而非内部属性
React Testing Library推荐测试组件的用户可见行为,而非DOM元素的内部属性。直接断言select元素的value更符合这个原则,且更可靠:
修改后的userEvent测试代码
test("Can Select Item", async () => { const user = userEvent.setup(); render( <select data-testid="test"> <option value="1" data-testid="Hey">Hey</option> <option value="2">There</option> </select> ); const select = screen.getByTestId("test"); await user.selectOptions(select, "1"); // 使用value而非文本,或直接传入option元素 expect(select).toHaveValue("1"); // 使用@testing-library/jest-dom的匹配器 });
修改后的fireEvent测试代码
test("Can Select Item", () => { render( <select data-testid="test"> <option value="1" data-testid="Hey">Hey</option> <option value="2">There</option> </select> ); const select = screen.getByTestId("test"); fireEvent.change(select, { target: { value: "1" } }); // 注意用fireEvent.change而非select expect(select).toHaveValue("1"); });
2. 如果一定要断言option的selected属性
若确实需要验证option的selected状态,需注意原生select的DOM行为:选中option时不会添加selected属性,而是设置元素的selected属性为true,直接访问该属性即可:
test("Can Select Item", async () => { const user = userEvent.setup(); render( <select data-testid="test"> <option value="1" data-testid="Hey">Hey</option> <option value="2">There</option> </select> ); const select = screen.getByTestId("test"); const heyOption = screen.getByTestId("Hey"); await user.selectOptions(select, heyOption); // 直接传入option元素 expect(heyOption.selected).toBe(true); // 直接访问selected属性 });
3. 版本兼容性说明
你的依赖版本组合无兼容性问题:React 18 + @testing-library/react 13 + @testing-library/user-event 13可以正常配合使用,核心问题是测试写法不符合RTL实践,以及对原生select DOM行为的误解。
内容的提问来源于stack exchange,提问作者user1694767
相关产品推荐
相关产品推荐

