如何在React Testing Library中触发shadcn/radix Select渲染Portal选项
测试shadcn Select组件时无法获取Portal渲染的选项问题
我开发了一个包含shadcn Select控件的组件,其中SelectTrigger组件的role为combobox,但最终生成的HTML是button元素。组件在浏览器中运行正常,但编写单元测试时遇到了问题:我需要验证5个预期选项是否按正确顺序显示且值符合预期。
之前用原生HTML select元素时,单元测试很简单——哪怕下拉框没展开,选项也会渲染在DOM里。但改用shadcn的Select组件后,选项通过Portal渲染,只有当下拉列表展开时才会出现在DOM中。
组件简化代码
import '@/components/scripture-ref-keyed-list.component.css'; import { ScriptureCheckDefinition, ScriptureItemDetail } from 'platform-bible-utils'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from './shadcn-ui/select'; export type ScriptureSrcItemDetail = ScriptureItemDetail & { /** Source/type of detail. Can be used for grouping. */ source: string | ScriptureCheckDefinition; }; const scrBookColId = 'scrBook'; const typeColId = 'source'; export default function ScriptureRefKeyedList() { // Define possible grouping options const scrBookGroupName = 'one'; const typeGroupName = 'two'; const groupingOptions = [ { label: 'No Grouping', value: [] }, { label: `Group by ${scrBookGroupName}`, value: [scrBookColId] }, { label: `Group by ${typeGroupName}`, value: [typeColId] }, { label: `Group by ${scrBookGroupName} and ${typeGroupName}`, value: [scrBookColId, typeColId], }, { label: `Group by ${typeGroupName} and ${scrBookGroupName}`, value: [typeColId, scrBookColId], }, ]; const handleSelectChange = (selectedGrouping: string) => { console.log(selectedGrouping); }; return ( <Select value={JSON.stringify([])} onValueChange={(value) => { handleSelectChange(value); }} > <SelectTrigger className="pr-mb-1"> <SelectValue /> </SelectTrigger> <SelectContent position="item-aligned"> <SelectGroup> {groupingOptions.map((option) => ( <SelectItem key={option.label} value={JSON.stringify(option.value)}> {option.label} </SelectItem> ))} </SelectGroup> </SelectContent> </Select> ); }
单元测试代码
import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; import ScriptureRefKeyedList from '@/components/scripture-ref-keyed-list.component'; describe('ScriptureRefKeyedList default display mode (with combobox for grouping option)', () => { beforeEach(() => { render(<ScriptureRefKeyedList />); }); it('should show grouping drop-down when clicked', async () => { const dropDown = screen.getByRole('combobox'); // Check that No Grouping is the current (default) option: expect(screen.getByText('No Grouping')).toBeInTheDocument(); expect(fireEvent.click(dropDown)).toBeTruthy(); await waitFor(() => { expect(screen.findByText('Group by one')).toBeInTheDocument(); }); }); });
已尝试的解决方案
- 用
fireEvent和userEvent触发多种浏览器中有效的事件:click、mouseDown,设置焦点后按下箭头键 - 尝试多种元素查询方式:
getByRole('option')、getByText、findByText,并通过调试器断点检查DOM - 测试多种等待DOM更新的方法:
await + waitFor、await + screen.findBy...、调整超时时间、await new Promise(r=>setTimeout(()=>r(), 0))、用act包裹操作
但无论尝试哪种方法,单元测试中的DOM都不会更新,除了默认选项“No Grouping”始终存在,查找其他选项的尝试全部失败。我知道很多人遇到过类似问题,部分方案对他人有效,但我试过所有方法后仍未解决。
内容的提问来源于stack exchange,提问作者Tom Bogle
相关产品推荐
相关产品推荐

