如何测试使用Portal的shadcn/ui Select组件选项选择功能?
如何在React Testing Library/Vitest中测试基于Portal渲染的shadcn/ui Select组件
Portal渲染的元素不会直接挂载到测试容器内,而是默认挂载到document.body,这是导致你无法直接用常规查询方法找到选项的核心原因。下面是具体的解决步骤和代码示例:
核心思路
- 用
userEvent模拟真实用户交互(替代fireEvent,更贴合实际操作逻辑) - 明确查询范围:针对Portal挂载的容器(通常是
document.body)查找选项 - 用异步查询方法等待选项渲染完成
完整测试示例
import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import CustomSelect from './CustomSelect'; // 你的封装组件 test('成功选择Portal内的"item 3"选项', async () => { // 初始化userEvent const user = userEvent.setup(); // 渲染组件 render(<CustomSelect />); // 找到Select触发器并点击展开选项 const selectTrigger = screen.getByRole('button', { name: /选择/i }); await user.click(selectTrigger); // 在document.body中查找目标选项(因为Portal挂载在这里) const targetOption = await screen.findByText('item 3', { container: document.body }); // 点击选中选项 await user.click(targetOption); // 验证状态更新:触发器文本变为选中内容 await waitFor(() => { expect(selectTrigger).toHaveTextContent('item 3'); }); });
特殊情况处理
如果你的Select组件自定义了Portal的挂载目标(比如指定了某个DOM元素作为根节点),需要调整查询的容器:
// 假设自定义Portal挂载到id为"custom-portal-root"的元素 const customPortalRoot = document.getElementById('custom-portal-root'); const targetOption = await screen.findByText('item 3', { container: customPortalRoot });
关键注意事项
- 优先用
userEvent:它会模拟完整的用户交互流程(比如聚焦、点击的完整事件链),而fireEvent仅触发单个事件,可能无法触发组件的展开逻辑。 - 用
findBy*系列查询:这类方法内置了等待逻辑,会自动等待异步渲染的Portal元素出现,无需额外嵌套waitFor(当然也可以用waitFor配合getBy*)。 - 验证状态时要等待:选项点击后的状态更新可能是异步的,用
waitFor确保断言时机正确。
内容的提问来源于stack exchange,提问作者EhsanKey_
相关产品推荐
相关产品推荐

