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

如何在Jest+RTL中修改shadcn/ui Select组件的值?

解决shadcn/ui Select结合react-hook-form的单元测试问题

shadcn/ui的Select组件基于Radix UI实现,测试时需要遵循Radix组件的交互逻辑,以下是可行的测试方案:

核心思路

利用React Testing Library的语义化查询(ARIA角色)定位组件,结合@testing-library/user-event模拟真实用户交互流程:打开下拉 → 选择选项 → 验证结果。

完整测试代码示例

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import ClientForm from './ClientForm'; // 你的表单组件

describe('Client Type Select Component', () => {
  it('should select an option and update form value correctly', async () => {
    // 初始化userEvent(需确保使用@testing-library/user-event@14+版本)
    const user = userEvent.setup();
    
    // 渲染表单组件
    render(<ClientForm />);

    // 1. 定位Select触发按钮:通过combobox角色和标签文本查找
    const selectTrigger = screen.getByRole('combobox', { name: /client type/i });
    // 2. 点击触发按钮打开下拉菜单
    await user.click(selectTrigger);

    // 3. 定位目标选项:通过option角色和选项文本查找
    const directOption = screen.getByRole('option', { name: 'Direct' });
    // 4. 点击选中选项
    await user.click(directOption);

    // 验证1:触发按钮显示选中的文本
    expect(selectTrigger).toHaveTextContent('Direct');

    // 验证2:react-hook-form的表单值更新(若需验证form内部状态)
    // 若组件暴露了form实例,可直接检查;否则可通过renderHook创建form传递给组件
    // 示例:
    // const { result } = renderHook(() => useForm({ defaultValues: { clientType: '' } }));
    // render(<ClientForm form={result.current} />);
    // expect(result.current.getValues('clientType')).toBe('Direct');
  });
});

关键注意事项

  • 必须使用**@testing-library/user-event@14及以上版本**:旧版本API不支持setup(),需改用userEvent.click()的异步写法。
  • 依赖语义化查询:避免用className或id定位组件,Radix组件会生成标准ARIA角色(combobox对应触发按钮,option对应下拉选项),这是最可靠的定位方式。
  • 等待交互完成:所有userEvent的操作都是异步的,必须加await确保组件状态更新后再执行验证。
  • 避免使用fireEvent:fireEvent是低级事件模拟,无法完整触发Radix组件内部的状态更新逻辑,必须用userEvent模拟真实用户行为。

内容的提问来源于stack exchange,提问作者James Bender

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 03:43:26