stepsCompleted: ['step-01-init', 'step-02-discovery', 'step-03-success', 'step-04-journeys', 'step-07-project-type', 'step-08-scoping', 'step-09-functional', 'step-10-nonfunctional', 'step-11-complete']
inputDocuments:
- name: 项目文档索引
path: docs/index.md
type: project-knowledge
loadedAt: '2026-01-07T12:00:00.000Z'
- name: 测试策略
path: docs/standards/testing-standards.md
type: testing-standards
loadedAt: '2026-01-07T12:00:00.000Z'
- name: Web UI测试规范
path: docs/standards/web-ui-testing-standards.md
type: testing-standards
loadedAt: '2026-01-07T12:00:00.000Z'
- name: 残疾人管理组件
path: allin-packages/disability-person-management-ui/src/components/DisabilityPersonManagement.tsx
type: source-code
loadedAt: '2026-01-07T12:00:00.000Z'
- name: 残疾人实体模型
path: allin-packages/disability-module/src/entities/disabled-person.entity.ts
type: source-code
loadedAt: '2026-01-07T12:00:00.000Z'
- name: E2E测试示例
path: web/tests/e2e/specs/admin/users.spec.ts
type: test-reference
loadedAt: '2026-01-07T12:00:00.000Z'
documentCounts:
briefs: 0
research: 0
projectDocs: 3
testReferences: 1
workflowType: 'prd'
lastStep: 6
---
Product Requirements Document - 188-179 招聘系统
作者: Root
日期: 2026-01-07
执行摘要
本项目旨在建立一套可复用的 E2E 测试模式和规范,从残疾人管理功能的测试实践中提取通用测试工具,特别是针对 Radix UI 组件的测试方法。
项目背景
188-179 招聘系统是一个大型企业级 Monorepo 招聘管理平台,采用 React 19 + Hono 4.x + TypeORM 技术栈。现有 E2E 测试使用 Playwright,遵循 Page Object 模式。
当前残疾人管理功能已经实现了完整的业务逻辑,包括:
- 照片上传管理(身份证、残疾证、个人照片等)
- 银行卡信息管理(支持多张卡)
- 备注管理(支持特殊需求标记)
- 回访记录管理
但 E2E 测试覆盖不完整,需要补充这些功能的测试用例。
核心目标
不仅为残疾人管理补充测试,更重要的是建立可复用的测试模式:
提取 Radix UI Select 测试规范(最关键)
- 静态枚举型 Select(如残疾类型、等级)
- 异步加载型 Select(如省份、城市)
- 统一的 API 接口和错误处理
提取其他常用表单组件测试模式
- 文件上传(照片、银行卡)
- 多步骤表单(填写 → 滚动 → 提交)
- 动态列表管理(添加/删除银行卡、备注)
- 对话框操作模式
输出两种形式
- 共享测试工具包:创建
packages/e2e-test-utils 新包
- 测试文档指南:更新到
docs/standards/ 下
特殊价值
这个项目的特殊之处在于:
从实践中提取模式:不是从零开始,而是从已有的残疾人管理测试实践中提炼通用方法
双重收益:
- 直接收益:完成残疾人管理的完整 E2E 测试覆盖
- 长期收益:建立测试规范,加速后续功能的测试开发
降低认知负担:新测试开发者不需要深入理解 Radix UI 内部机制,只需调用统一 API
提高测试稳定性:统一的等待策略、错误处理和重试逻辑
高度复用性:新增/编辑残疾人都会用到,未来其他管理功能也可复用
为什么现在做
- 残疾人管理功能已实现,是提取模式的最佳时机
- 现有调试测试已验证了基本流程,可以在此基础上完善
- 未来还有更多管理功能需要类似测试,提前建立规范能避免重复工作
项目分类
技术类型: developer_tool(测试工具/基础设施)
领域: general(通用测试模式,不限于特定业务领域)
复杂度: low(相对独立的工具函数 + 文档,不影响核心业务逻辑)
项目上下文: 棕地项目 - 扩展现有测试基础设施,遵循现有 Page Object 模式
成功标准
用户成功
测试开发者视角的成功指标:
快速上手
- 新测试开发者在 30 分钟内能写出第一个包含 Radix UI Select 的测试用例
- 不需要深入研究 Radix UI 内部机制或 DOM 结构
一次成功
- 第一次运行测试就通过,不需要反复调试时序问题
- 测试连续运行 20 次全部通过,无 flaky 失败
易于维护
- 其他团队成员接手测试时,能在 10 分钟内理解并修改测试代码
- 测试代码清晰表达意图,不需要注释就能看懂
稳定的开发体验
- 测试失败时能快速定位是产品问题还是测试问题
- 有清晰的错误提示指向问题所在
业务成功
短期(1-3个月)
- E2E 测试编写时间减少 50%(相比之前每次重新摸索)
- 残疾人管理功能的测试覆盖率达到关键用户流程 100%
- 工具函数被至少 1 个其他管理功能复用
中期(3-6个月)
- 新功能的 E2E 测试开发周期显著缩短
- E2E 测试的 flaky 率降低到 5% 以下
- 至少 3 个其他管理功能复用这套测试模式
长期(6-12个月)
- 建立 E2E 测试规范成为团队标准
- 新人 E2E 测试培训时间减少 70%
- 测试工具函数成为项目的标准基础设施
技术成功
代码质量
- 共享工具函数的测试覆盖率 ≥ 80%
- TypeScript 类型安全,无 any 类型
- 代码通过 ESLint 和 TypeScript 严格模式检查
可扩展性
- 新增组件测试模式只需扩展,无需修改核心逻辑
- 支持未来的 Radix UI 版本升级
- 工具函数设计支持配置和自定义
文档完整性
- 测试指南覆盖所有提取的模式
- 每个模式至少提供 1 个实际使用示例
- 文档清晰说明静态 vs 异步 Select 的区别
可衡量的结果
| 指标 |
当前状态 |
目标状态 |
测量方式 |
| Radix Select 测试编写时间 |
需要研究/摸索 |
5 分钟内完成 |
计时实验 |
| 测试稳定性(通过率) |
未知 |
20 次连续运行 100% 通过 |
自动化运行 |
| 工具函数测试覆盖率 |
0% |
≥ 80% |
代码覆盖率报告 |
| 文档完整性 |
无 |
覆盖 6 种模式 + 示例 |
文档检查清单 |
| 残疾人管理测试覆盖率 |
基础表单 |
完整 CRUD + 子功能 |
代码覆盖率报告 |
| 模式复用次数 |
0 |
至少 3 个功能复用 |
使用统计 |
产品范围
MVP - Minimum Viable Product
核心:从残疾人 E2E 测试中抽取可复用工具函数
1. 创建新包 packages/e2e-test-utils ⭐(最重要)
独立于 @d8d/shared-test-util(后端集成测试),专门用于 Playwright E2E 测试:
packages/e2e-test-utils/
├── package.json
├── src/
│ ├── index.ts
│ ├── radix-select.ts # Radix UI Select 工具
│ ├── file-upload.ts # 文件上传工具
│ ├── form-helper.ts # 表单辅助函数
│ ├── dialog.ts # 对话框操作
│ └── dynamic-list.ts # 动态列表管理
├── tests/ # 工具函数的单元测试
└── README.md
核心工具函数:
selectRadixOption(page, label, value) - 静态枚举型 Radix UI Select
selectRadixOptionAsync(page, label, value, options) - 异步加载型 Select(省份、城市)
uploadFileToField(page, selector, fileName) - 文件上传(照片、银行卡)
fillMultiStepForm(page, steps) - 多步骤表单流程
addDynamicListItem(page, itemType, data) - 动态列表添加
handleDialog(page, action) - 对话框操作模式
2. 残疾人管理 E2E 测试(验证工具函数)
使用提取的工具函数编写的完整测试:
- 照片上传功能测试
- 银行卡管理功能测试
- 备注功能测试
- 回访功能测试
- 完整流程测试(所有功能组合)
3. 基础测试文档
- 快速入门指南
- 2-3 个实际使用示例
- 常见问题和解决方案
价值主张: 工具函数是核心资产,测试用例证明它们可用。
Growth Features (Post-MVP)
扩展工具函数库:
- Date Picker、Slider、Tabs 等 Radix 组件测试模式
- 表单验证错误处理测试模式
- 网络请求 Mock 和断言辅助函数
开发体验增强:
- VS Code snippets 快速插入测试代码
- CLI 命令生成测试模板
- 交互式调试模式(慢动作、可视化等待)
质量保障集成:
- 集成到 CI/CD 的自动化测试报告
- 测试覆盖率趋势追踪
- Flaky 测试自动检测和报告
Vision (Future)
智能化测试开发:
- 自动发现页面中的 Radix 组件并生成测试骨架
- AI 辅助测试编写(描述行为自动生成测试)
- 智能等待策略(根据组件特性自动调整)
可视化与监控:
- 测试覆盖率可视化仪表盘
- 测试执行时间热力图
- 跨项目的测试模式库和最佳实践分享
生态系统:
- 支持更多 UI 库(Ant Design、Material-UI)
- 开源为独立的 Playwright 插件
- 社区贡献的测试模式扩展包
用户旅程
旅程 1:张伟 - 赶时间的测试开发者
人物设定:
- 姓名: 张伟
- 角色: 全栈开发者,需要为新功能编写 E2E 测试
- 情境: 产品经理刚刚要求他为残疾人管理功能补充完整的 E2E 测试
- 痛点: 之前每次写测试都要花大量时间研究 Radix UI 的 DOM 结构,测试经常因为时序问题失败
- 目标: 快速完成测试任务,测试要稳定可靠
他的故事:
周一早上,张伟接到任务:"残疾人管理功能需要补充照片上传、银行卡管理等功能的 E2E 测试,周三前完成。"
张伟叹了口气。上次写测试时,他花了整整一下午研究 Radix UI Select 的测试方法,还要处理各种时序问题。测试写完后还经常 flaky,团队 CI 管道里经常因为这个功能失败。
他打开项目,注意到有个新包 packages/e2e-test-utils。他好奇地点开 README,发现里面正好有他需要的 Radix UI Select 测试工具。
他决定试一试。只需要导入工具函数,然后调用 selectRadixOption(page, '残疾类型', '视力残疾') 就可以了。不需要研究 DOM 结构,不需要处理复杂的等待逻辑。
第一个小时: 张伟轻松完成了照片上传和银行卡管理的测试。这些功能之前他一直觉得很难测试,现在居然这么简单。
第二个小时: 他继续添加备注和回访功能的测试。遇到异步加载的省份选择器时,他发现工具函数已经处理了等待逻辑,直接用 selectRadixOptionAsync 就可以了。
第三个小时: 张伟写完最后一个测试,点击运行。所有测试一次性通过!他有些不敢相信,又运行了 5 次,全部稳定通过。
结果: 周二下午,张伟不仅完成了所有测试,还把工具函数推荐给了团队其他成员。他甚至有时间优化测试代码,让测试更清晰易懂。
旅程需求总结
这些用户旅程揭示了以下核心需求:
测试开发者(张伟)的需求:
- 简单易用的 API,不需要深入理解 Radix UI
- 自动处理等待和时序问题
- 清晰的错误提示和调试信息
- 完整的使用文档和示例
- 工具函数开箱即用,快速集成
新手测试开发者的需求:
- 快速入门指南,降低学习曲线
- 渐进式的学习路径(从简单到复杂)
- 丰富的实际代码示例
- 常见问题和解决方案文档
QA 工程师的需求:
- 测试工具函数的可靠性保障
- 测试覆盖率和质量报告
- 测试最佳实践指南
- 团队协作和代码审查支持
Tech Lead 的需求:
- 代码质量和可维护性标准
- 测试模式的一致性和规范性
- 技术决策文档和架构说明
- 团队培训和知识传递材料
Developer Tool Specific Requirements
Project-Type Overview
188-179 E2E 测试工具包是一个开发者工具库,专注于简化 Playwright E2E 测试中对 Radix UI 组件的测试。作为内部工具包,它需要提供清晰的 API、完整的类型安全和易用的开发体验。
Technical Architecture Considerations
语言与类型系统:
- 纯 TypeScript 实现,目标 ES2020+
- 严格类型检查,无
any 类型
- 完整的 JSDoc 注释用于 IDE 提示
包结构:
packages/e2e-test-utils/
├── package.json
├── src/
│ ├── index.ts # 主导出
│ ├── radix-select.ts # Radix UI Select 工具
│ ├── file-upload.ts # 文件上传工具
│ ├── form-helper.ts # 表单辅助函数
│ ├── dialog.ts # 对话框操作
│ └── dynamic-list.ts # 动态列表管理
├── tests/ # 工具函数的单元测试
└── README.md
依赖管理:
- Peer dependency:
@playwright/test (由测试项目提供)
- 无运行时依赖,保持轻量
- 开发依赖: TypeScript, Vitest (用于自测)
Language & API Matrix
| 组件类型 |
工具函数 |
参数 |
返回值 |
| Radix UI Select (静态) |
selectRadixOption(page, label, value) |
Page, 标签文本, 选项值 |
Promise<void> |
| Radix UI Select (异步) |
selectRadixOptionAsync(page, label, value, options) |
Page, 标签文本, 选项值, 等待配置 |
Promise<void> |
| 文件上传 |
uploadFileToField(page, selector, fileName) |
Page, 选择器, 文件名 |
Promise<void> |
| 多步骤表单 |
fillMultiStepForm(page, steps) |
Page, 步骤数组 |
Promise<void> |
| 动态列表 |
addDynamicListItem(page, itemType, data) |
Page, 项类型, 数据 |
Promise<void> |
| 对话框操作 |
handleDialog(page, action) |
Page, 操作类型 |
Promise<void> |
Installation Methods
在测试项目中安装:
# 在 web/ 目录下
pnpm add -D @d8d/e2e-test-utils@workspace:*
在测试文件中导入:
import { selectRadixOption, uploadFileToField } from '@d8d/e2e-test-utils';
API Surface
核心工具函数签名:
/**
* 选择 Radix UI 下拉框的静态选项
* @param page Playwright Page 对象
* @param label 下拉框标签文本
* @param value 要选择的选项值
*/
export async function selectRadixOption(
page: Page,
label: string,
value: string
): Promise<void>
/**
* 选择 Radix UI 下拉框的异步加载选项
* @param page Playwright Page 对象
* @param label 下拉框标签文本
* @param value 要选择的选项值
* @param options 等待配置 (超时、重试等)
*/
export async function selectRadixOptionAsync(
page: Page,
label: string,
value: string,
options?: AsyncSelectOptions
): Promise<void>
/**
* 上传文件到指定字段
* @param page Playwright Page 对象
* @param selector 文件输入选择器
* @param fileName 要上传的文件名(相对于 fixtures 目录)
*/
export async function uploadFileToField(
page: Page,
selector: string,
fileName: string
): Promise<void>
Code Examples
示例 1:选择静态枚举型下拉框
import { selectRadixOption } from '@d8d/e2e-test-utils';
// 选择残疾类型
await selectRadixOption(page, '残疾类型', '视力残疾');
示例 2:选择异步加载的下拉框
import { selectRadixOptionAsync } from '@d8d/e2e-test-utils';
// 选择省份(异步加载)
await selectRadixOptionAsync(page, '省份', '广东省', {
timeout: 5000,
waitForOption: true
});
示例 3:上传照片
import { uploadFileToField } from '@d8d/e2e-test-utils';
// 上传身份证照片
await uploadFileToField(page, '[data-testid="id-card-photo-input"]', 'sample-id-card.jpg');
Migration Guide
从现有的内联测试代码迁移到工具函数:
之前(内联代码):
// 需要手动处理 Radix UI 的复杂 DOM 结构和时序
await page.click(`text=残疾类型`);
await page.waitForSelector('[role="option"]');
await page.click(`[role="option"]:has-text("视力残疾")`);
之后(使用工具函数):
import { selectRadixOption } from '@d8d/e2e-test-utils';
await selectRadixOption(page, '残疾类型', '视力残疾');
迁移步骤:
- 安装工具包:
pnpm add -D @d8d/e2e-test-utils@workspace:*
- 导入需要的工具函数
- 替换内联的 Radix UI 操作代码
- 验证测试通过
Implementation Considerations
等待策略:
- 使用
waitForLoadState('networkidle') 处理异步加载
- 为静态选项设置合理默认超时(2秒)
- 为异步选项提供可配置超时
错误处理:
- 提供清晰的错误消息,指出具体失败点
- 区分"元素未找到"和"超时"错误
- 包含上下文信息(选择器、标签、期望值)
测试稳定性:
- 使用 Playwright 的 auto-waiting 机制
- 添加显式等待防止时序问题
- 支持重试机制处理 flaky 网络请求
可扩展性:
- 工具函数支持配置对象参数
- 预留钩子函数用于自定义行为
- 设计支持未来 Radix UI 版本升级
Project Scoping & Phased Development
MVP Strategy & Philosophy
MVP 方法: Platform MVP - 构建可扩展的测试工具基础设施
核心理念:不仅是解决当前残疾人管理测试的需求,更要建立一个可持续扩展的平台,让未来所有功能的 E2E 测试都能受益。
资源需求:
- 团队规模:1-2 名开发者
- 技能要求:TypeScript、Playwright、Radix UI 理解
- 时间估算:MVP 1-2 周完成
MVP Feature Set (Phase 1)
核心用户旅程支持:
- ✅ 张伟的快速测试开发旅程(完整的残疾人管理测试)
必须具备的能力(MVP):
1. Radix UI Select 测试工具(最关键)
selectRadixOption() - 静态枚举型下拉框
selectRadixOptionAsync() - 异步加载型下拉框
- 完整的错误处理和等待策略
- 清晰的错误提示信息
2. 文件上传测试工具
uploadFileToField() - 通用文件上传函数
- 支持 fixtures 目录管理
- 支持多文件上传场景
3. 表单辅助函数
fillMultiStepForm() - 多步骤表单流程
scrollToSection() - 滚动到特定区域
- 表单验证错误处理
4. 动态列表管理
addDynamicListItem() - 添加动态列表项
deleteDynamicListItem() - 删除动态列表项
- 支持银行卡、备注等多类型列表
5. 对话框操作模式
handleDialog() - 统一的对话框操作
waitForDialogClosed() - 等待对话框关闭
cancelDialog() - 取消对话框操作
6. 残疾人管理 E2E 测试(验证工具函数可用)
- 照片上传功能测试
- 银行卡管理功能测试
- 备注功能测试
- 回访功能测试
- 完整流程测试
7. 基础文档
- README 快速入门
- 每个工具函数的使用示例
- 常见问题解答
MVP 排除的功能(留给后续版本):
- VS Code snippets
- CLI 测试生成器
- 交互式调试模式
- 其他 Radix 组件(Date Picker、Slider 等)
- AI 辅助测试生成
Post-MVP Features
Phase 2 (Post-MVP) - 增长阶段:
扩展组件支持:
- Date Picker 测试工具
- Slider 测试工具
- Tabs 测试工具
- 表单验证错误处理模式
开发体验增强:
- VS Code snippets 快速插入
- Playwright trace 集成
- 更详细的错误上下文信息
质量保障:
- CI/CD 集成测试报告
- 测试覆盖率趋势追踪
- Flaky 测试检测和报告
复用验证:
- 至少 3 个其他管理功能复用工具函数
- 收集用户反馈并迭代优化
Phase 3 (Expansion) - 扩展阶段:
高级功能:
- CLI 命令生成测试模板
- 交互式调试模式(慢动作、可视化等待)
- 网络请求 Mock 和断言辅助函数
- 多窗口/多标签页测试工具
智能化:
- 自动发现页面中的 Radix 组件并生成测试骨架
- AI 辅助测试编写(描述行为自动生成测试)
- 智能等待策略(根据组件特性自动调整)
生态系统:
- 支持更多 UI 库(Ant Design、Material-UI)
- 开源为独立的 Playwright 插件
- 社区贡献的测试模式扩展包
Risk Mitigation Strategy
技术风险:
- 风险: Radix UI DOM 结构变化导致工具函数失效
- 缓解:
- 使用稳定的选择器策略(role、data-testid)
- 设计可扩展的函数签名,支持自定义选择器
- 工具函数自测,快速发现问题
市场/采用风险:
- 风险: 团队成员不愿意使用新工具,继续用老方法
- 缓解:
- MVP 验证:先在残疾人管理测试中证明价值
- 渐进式推广:让早期使用者(张伟)推荐给团队
- 完善文档:降低学习成本,提供即时价值
资源风险:
- 风险: 开发时间超出预期
- 缓解:
- 明确 MVP 边界:只实现 6 个核心函数
- 时间盒:MVP 限制在 1-2 周
- 降级方案:如果时间紧张,优先完成 Select 工具函数(最核心)
质量风险:
- 风险: 工具函数本身有 bug,导致测试不稳定
- 缓解:
- 工具函数编写单元测试
- 在残疾人管理测试中验证
- 代码审查确保质量
- 20 次连续运行稳定性测试
Scope Decision Rationale
为什么 MVP 范围这样设计:
聚焦核心价值:Select 组件是最难测试的,也是最常用的,优先解决它
验证驱动:通过残疾人管理测试验证工具函数的可用性,确保不是纸上谈兵
渐进式扩展:MVP 验证成功后再扩展到其他组件和功能
可测量成果:每个功能都有明确的成功标准(时间、覆盖率、复用次数)
风险可控:范围明确,时间盒限制,有降级方案
MVP 成功标志:
- ✅ 6 个核心工具函数实现并测试通过
- ✅ 残疾人管理 E2E 测试覆盖所有子功能
- ✅ 测试连续运行 20 次,100% 通过
- ✅ 至少 1 个团队成员(非开发者)成功使用工具函数编写测试
Functional Requirements
Radix UI Select 组件测试支持
- FR1: 测试开发者可以使用工具函数选择静态枚举型 Radix UI Select 下拉框的选项
- FR2: 测试开发者可以使用工具函数选择异步加载型 Radix UI Select 下拉框的选项
- FR3: 工具函数可以自动处理 Radix UI Select 的 DOM 结构和交互流程
- FR4: 工具函数可以等待异步加载的选项出现在下拉列表中
- FR5: 工具函数可以提供清晰的错误提示,包含标签、期望值等上下文信息
- FR6: 工具函数可以区分"元素未找到"和"超时"错误类型
文件上传测试支持
- FR7: 测试开发者可以使用工具函数上传文件到指定的文件输入字段
- FR8: 工具函数可以从 fixtures 目录加载测试文件
- FR9: 工具函数可以支持多文件上传场景
- FR10: 工具函数可以验证文件上传是否成功完成
表单交互测试支持
- FR11: 测试开发者可以使用工具函数填写多步骤表单
- FR12: 工具函数可以滚动页面到特定的表单区域
- FR13: 工具函数可以处理表单验证错误场景
- FR14: 测试开发者可以使用工具函数提交表单并等待响应
- FR15: 工具函数可以支持常见的表单字段类型(文本、选择器、日期等)
动态列表测试支持
- FR16: 测试开发者可以使用工具函数向动态列表中添加新项
- FR17: 测试开发者可以使用工具函数从动态列表中删除项
- FR18: 工具函数可以支持不同类型的动态列表项(银行卡、备注等)
- FR19: 工具函数可以验证动态列表项添加或删除后的状态
- FR20: 工具函数可以处理动态列表的异步更新场景
对话框操作测试支持
- FR21: 测试开发者可以使用工具函数统一操作对话框(确认、取消、关闭)
- FR22: 工具函数可以等待对话框完全关闭后再继续执行
- FR23: 工具函数可以处理对话框内的表单填写和提交
- FR24: 工具函数可以验证对话框是否按预期打开或关闭
测试工具包基础设施
- FR25: 测试开发者可以通过 npm workspace 协议安装测试工具包
- FR26: 工具包可以作为 peer dependency 依赖 Playwright,不增加运行时依赖
- FR27: 工具包提供完整的 TypeScript 类型定义和类型提示
- FR28: 工具包的所有导出函数都有完整的 JSDoc 注释
- FR29: 工具包使用严格类型检查,不使用 any 类型
- FR30: 工具包支持目标 ES2020+ 的 JavaScript 环境
- FR31: 工具包的每个工具函数都可以独立导入和使用
- FR32: 工具包可以与其他测试工具和库兼容使用
文档和开发者支持
- FR33: 测试开发者可以通过 README 快速了解工具包的用途和安装方法
- FR34: 文档提供每个工具函数的详细使用示例
- FR35: 文档提供静态 Select 和异步 Select 的区别说明
- FR36: 文档提供从现有测试代码迁移到工具函数的指南
- FR37: 文档提供常见问题和解决方案
- FR38: 文档提供残疾人管理测试作为完整的使用示例
- FR39: 测试开发者可以在 30 分钟内使用工具函数编写第一个测试
- FR40: 工具包的使用示例覆盖所有 6 个核心工具函数
测试质量和稳定性保障
- FR41: 工具函数使用 Playwright 的 auto-waiting 机制防止时序问题
- FR42: 工具函数为静态选项设置合理的默认超时配置
- FR43: 工具函数为异步选项提供可配置的超时参数
- FR44: 工具函数可以支持重试机制处理不稳定的网络请求
- FR45: 工具函数可以在测试连续运行 20 次时保持 100% 通过率
可扩展性和维护性
- FR46: 工具函数支持配置对象参数,允许自定义行为
- FR47: 工具函数设计支持未来的 Radix UI 版本升级
- FR48: 工具函数使用稳定的选择器策略(role、data-testid)
- FR49: 工具包预留扩展接口,支持新增其他 Radix 组件测试模式
- FR50: 工具包的代码结构清晰,便于团队贡献和维护
Non-Functional Requirements
可靠性
测试稳定性(最关键):
- NFR1: 工具函数在相同条件下连续运行 20 次,必须保持 100% 通过率,无 flaky 失败
- NFR2: 工具函数能够正确处理异步加载场景,避免时序问题导致的测试失败
- NFR3: 当 DOM 元素暂时不可用时,工具函数提供清晰的错误消息,而不是超时无响应
- NFR4: 工具函数能够区分产品 bug 和测试代码问题,帮助开发者快速定位问题根源
错误处理和诊断:
- NFR5: 当选择操作失败时,错误消息包含以下信息:
- 下拉框标签名称
- 期望选择的值
- 实际可用的选项列表
- 失败原因(元素未找到、超时、选项不存在等)
- NFR6: 当文件上传失败时,错误消息包含文件路径、选择器、失败原因
- NFR7: 错误消息格式统一,便于日志分析和问题定位
性能
测试执行效率:
- NFR8: 单个 Radix UI Select 选择操作(静态)应在 2 秒内完成
- NFR9: 单个 Radix UI Select 选择操作(异步)应在 5 秒内完成(默认超时)
- NFR10: 工具函数本身的开销不超过 100ms(不包括 Playwright 操作时间)
- NFR11: 使用工具函数的测试比手动编写 DOM 操作的测试执行时间差异 < 10%
等待策略优化:
- NFR12: 静态选项使用合理的默认超时(2 秒),避免不必要的等待
- NFR13: 异步选项提供可配置的超时参数,默认值为 5 秒
- NFR14: 工具函数使用 Playwright 的 auto-waiting 机制,减少显式等待的需要
集成性
Playwright 兼容性:
- NFR15: 工具包兼容 Playwright 最新稳定版本和上一个 LTS 版本
- NFR16: 工具包可以作为 peer dependency 引用,不增加运行时依赖
- NFR17: 工具函数接受标准 Playwright Page 对象作为参数
- NFR18: 工具包不依赖特定版本的 Playwright,使用灵活的版本范围
测试框架集成:
- NFR19: 工具函数可以在任何使用 Playwright 的测试框架中运行(Vitest、Jest 等)
- NFR20: 工具包不修改全局配置,不需要额外的测试框架配置
- NFR21: 工具函数可以与现有的 Page Object 模式无缝集成
Monorepo 集成:
- NFR22: 工具包通过 pnpm workspace 协议安装,支持本地开发
- NFR23: 工具包的构建产物与项目的 TypeScript 配置兼容
- NFR24: 工具包的类型定义可以自动被 IDE 识别和提示
代码质量
类型安全:
- NFR25: 工具包使用 TypeScript 严格模式,无
any 类型
- NFR26: 所有导出函数都有完整的参数类型和返回值类型
- NFR27: 类型定义支持 IDE 自动补全和类型检查
- NFR28: 类型错误在编译时被捕获,不在运行时暴露
代码可维护性:
- NFR29: 工具包的代码覆盖率 ≥ 80%
- NFR30: 每个工具函数都有对应的单元测试
- NFR31: 代码遵循项目的 ESLint 和 Prettier 配置
- NFR32: 函数复杂度保持在低水平(圈复杂度 < 10)
文档质量:
- NFR33: 每个导出函数都有完整的 JSDoc 注释
- NFR34: README 包含快速入门、安装说明、基本用法
- NFR35: 每个工具函数至少有 1 个实际使用示例
- NFR36: 文档说明静态 Select 和异步 Select 的区别和使用场景
开发者体验:
- NFR37: 新测试开发者可以在 30 分钟内使用工具函数编写第一个测试
- NFR38: 工具函数的命名清晰直观,不需要频繁查看文档
- NFR39: 函数参数设计简洁,必需参数 ≤ 3 个
- NFR40: 错误消息对新手友好,包含问题诊断和建议修复步骤
兼容性
浏览器和环境:
- NFR41: 工具函数在 Playwright 支持的所有浏览器中正常工作(Chromium、Firefox、WebKit)
- NFR42: 工具函数在 headless 和 headed 模式下都能正常工作
- NFR43: 工具函数在 CI/CD 环境中稳定运行
版本兼容性:
- NFR44: 工具包支持 Node.js 当前 LTS 版本和上一个 LTS 版本
- NFR45: 工具包的设计考虑未来 Radix UI 版本升级,使用稳定的选择器策略
- NFR46: 重大版本变更时提供迁移指南