生成日期: 2026-01-09
测试文件: web/tests/e2e/specs/admin/disability-person-complete.spec.ts
工具版本: @d8d/e2e-test-utils (from Story 2.1-2.3)
selectRadixOption 工具无法找到 [role="listbox"] 元素类别: 工具 bug 严重程度: 高 - 阻塞所有使用静态 Select 的测试 状态: 待修复
问题描述:
selectRadixOption 工具在点击 Radix UI Select 触发器后,等待 [role="listbox"] 元素出现,但该元素从未出现,导致测试超时失败。
复现步骤:
pnpm test:e2e:chromium disability-person-completeselectRadixOption(page, "残疾类型 *", "视力残疾") 选择残疾类型[role="listbox"] 出现(超时 2000ms)错误信息:
TimeoutError: page.waitForSelector: Timeout 2000ms exceeded.
Call log:
- waiting for locator('[role=listbox]') to be visible
at ../../../../packages/e2e-test-utils/src/radix-select.ts:37
预期行为:
点击触发器后,Radix UI Select 应该渲染带有 [role="listbox"] 属性的内容容器。
实际行为:
从 Playwright 错误上下文快照可以看到,点击后选项出现在 [role="combobox"] 内部,而非独立的 [role="listbox"]:
- combobox "残疾类型 *" [active] [ref=e26]:
- option "请选择残疾类型" [selected]
- option "视力残疾"
- option "听力残疾"
- option "言语残疾"
- option "肢体残疾"
- option "智力残疾"
- option "精神残疾"
- option "多重残疾"
根本原因分析:
有两种可能:
Radix UI Select v2.2.5 渲染方式不同: 该版本的 Radix UI Select 可能不使用 [role="listbox"] 角色,或者将其应用在不同的元素上。
工具假设错误: 工具期望的 DOM 结构与实际 Radix UI Select 的实现不匹配。
建议解决方案:
验证 Radix UI Select 的实际角色:
# 在浏览器中手动测试,检查打开 Select 时的 DOM 结构
# 或者使用 Playwright 的 page.content() 查看完整 HTML
修复工具以支持实际的 DOM 结构:
[role="listbox"] 的依赖,或改为可选[role="option"] 元素出现修复建议代码:
// packages/e2e-test-utils/src/radix-select.ts
export async function selectRadixOption(page: Page, label: string, value: string): Promise<void> {
console.debug(`[selectRadixOption] 开始选择: label="${label}", value="${value}"`);
const trigger = await findTrigger(page, label, value);
console.debug(`[selectRadixOption] 找到触发器,准备点击`);
await trigger.click();
// 修复: 不等待 listbox,直接等待选项出现
console.debug(`[selectRadixOption] 已点击触发器,等待选项`);
await page.waitForSelector("[role=option]", { timeout: DEFAULT_TIMEOUTS.static, state: "visible" });
console.debug(`[selectRadixOption] 选项已出现`);
const availableOptions = await page.locator("[role=option]").allTextContents();
console.debug(`[selectRadixOption] 可用选项:`, availableOptions);
await findAndClickOption(page, value, availableOptions);
console.debug(`[selectRadixOption] 选择完成`);
}
相关文件:
packages/e2e-test-utils/src/radix-select.ts:37packages/e2e-test-utils/src/radix-select.ts:230 (async version)类别: 工具 bug 严重程度: 高 - 阻塞所有使用异步 Select 的测试 状态: 待验证(未运行到相关代码)
问题描述:
selectRadixOptionAsync 工具在第 230 行也使用 page.waitForSelector('[role="listbox"]'),预计会遇到与静态 Select 相同的问题。
相关代码:
// packages/e2e-test-utils/src/radix-select.ts:230
await page.waitForSelector('[role="listbox"]', {
timeout: DEFAULT_TIMEOUTS.static,
state: 'visible'
});
建议解决方案: 应用与问题 #1 相同的修复方案。
简化选择器策略:
findTrigger 函数有 4 种策略,过于复杂更好的错误消息:
更新 README 中的 Radix UI 版本说明:
添加常见问题排查指南:
减少硬编码超时:
DEFAULT_TIMEOUTS.static = 2000 可能不够并行等待优化:
Running 6 tests using 1 worker
========== 开始完整功能测试 ==========
[步骤1] 打开新增残疾人对话框...
✓ 对话框已打开
[步骤2] 填写基本信息...
[selectRadixOption] 开始选择: label="残疾类型 *", value="视力残疾"
选择器策略1失败: [data-testid="残疾类型 *-trigger"]
选择器策略2失败: [aria-label="残疾类型 *"][role="combobox"]
选择器策略3: 尝试 getByRole(combobox, { name: "残疾类型 *" })
选择器策略3成功: 找到 combobox "残疾类型 *"
[selectRadixOption] 找到触发器,准备点击
[selectRadixOption] 已点击触发器,等待 listbox
✘ 1 [chromium] › 残疾人管理 - 完整功能测试 › 完整流程:新增残疾人
TimeoutError: page.waitForSelector: Timeout 2000ms exceeded.
Call log:
- waiting for locator('[role=listbox]') to be visible
1 failed
5 did not run