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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 23:45:23