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

如何测试使用Portal的shadcn/ui Select组件选项选择功能?

如何在React Testing Library/Vitest中测试基于Portal渲染的shadcn/ui Select组件

Portal渲染的元素不会直接挂载到测试容器内,而是默认挂载到document.body,这是导致你无法直接用常规查询方法找到选项的核心原因。下面是具体的解决步骤和代码示例:

核心思路

  1. 用userEvent模拟真实用户交互(替代fireEvent,更贴合实际操作逻辑)
  2. 明确查询范围:针对Portal挂载的容器(通常是document.body)查找选项
  3. 用异步查询方法等待选项渲染完成

完整测试示例

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_

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 06:22:15