stepsCompleted: ['step-01-validate-prerequisites', 'step-02-design-epics', 'step-03-create-stories'] inputDocuments:
This document provides the complete epic and story breakdown for 188-179-template-6,从残疾人管理 E2E 测试实践中提取可复用的测试工具包。
Radix UI Select 组件测试支持 (FR1-FR6):
文件上传测试支持 (FR7-FR10):
表单交互测试支持 (FR11-FR15):
动态列表测试支持 (FR16-FR20):
对话框操作测试支持 (FR21-FR24):
测试工具包基础设施 (FR25-FR32):
文档和开发者支持 (FR33-FR40):
测试质量和稳定性保障 (FR41-FR45):
可扩展性和维护性 (FR46-FR50):
可靠性 (NFR1-NFR7):
性能 (NFR8-NFR14):
集成性 (NFR15-NFR24):
代码质量 (NFR25-NFR40):
any 类型兼容性 (NFR41-NFR46):
从 Architecture 文档提取的技术需求:
包结构需求:
packages/e2e-test-utils,与现有的 @d8d/shared-test-util(后端集成测试)分离src/ 分为 radix-select.ts, file-upload.ts, form-helper.ts, dialog.ts, dynamic-list.tstypes.ts, errors.ts, constants.tsindex.ts,支持 tree-shakingAPI 设计需求:
selectRadixOption)Async 后缀(如 selectRadixOptionAsync)Options 后缀(如 AsyncSelectOptions)类型系统需求:
types.ts 存放共享类型(BaseOptions),各模块文件存放特定类型BaseOptionsany 类型选择器策略需求:
data-testid错误处理需求:
E2ETestError + ErrorContext测试策略需求:
tests/test-app/ 使用 Vite + React@d8d/shared-ui-components 组件常量定义需求:
DEFAULT_TIMEOUTS.static = 2000, async = 5000, networkIdle = 10000SELECTOR_STRATEGIES 数组文档需求:
遵循项目标准:
docs/standards/testing-standards.md 中的测试规范docs/standards/web-ui-testing-standards.md 中的 Web UI 测试规范docs/standards/e2e-radix-testing.md 中的 Radix UI E2E 测试标准(核心标准文档)从 E2E Radix UI 测试标准提取的详细需求:
核心工具函数签名(必须按此实现):
// Radix UI Select 工具
selectRadixOption(page: Page, label: string, value: string): Promise<void>
selectRadixOptionAsync(page: Page, label: string, value: string, options?: AsyncSelectOptions): Promise<void>
// 文件上传工具
uploadFileToField(page: Page, selector: string, fileName: string): Promise<void>
// 表单辅助工具
fillMultiStepForm(page: Page, steps: FormStep[]): Promise<void>
scrollToSection(page: Page, sectionName: string): Promise<void>
// 动态列表工具
addDynamicListItem(page: Page, itemType: string, data: Record<string, any>): Promise<void>
deleteDynamicListItem(page: Page, itemType: string, index: number): Promise<void>
// 对话框工具
handleDialog(page: Page, action: 'confirm' | 'cancel' | 'close'): Promise<void>
waitForDialogClosed(page: Page): Promise<void>
cancelDialog(page: Page): Promise<void>
DOM 结构理解需求:
data-radix-select-trigger 触发器,role="listbox" 选项列表,role="option" 单个选项role="dialog" 对话框容器data-value 用于选项值,data-state 用于状态跟踪选择器策略实现细节:
// 触发器选择器优先级
const TRIGGER_SELECTORS = [
`[data-testid="${label}-trigger"]`, // 最高优先级
`text="${label}"`, // 文本匹配
`[role="combobox"]` // 兜底
];
// 选项选择器优先级
const OPTION_SELECTORS = [
`[role="option"][data-value="${value}"]`, // data-testid + data-value
`[role="option"]:has-text("${value}")` // 文本匹配兜底
];
性能标准(来自测试标准文档): | 操作 | 目标时间 | 最大可接受时间 | |------|---------|---------------| | 静态 Select 选择 | < 1s | 2s | | 异步 Select 选择 | < 3s | 5s | | 文件上传 | < 2s | 5s | | 表单提交 | < 2s | 5s |
Fixtures 目录结构标准:
web/tests/
└── fixtures/
├── images/ # 测试图片(身份证照片、残疾证照片等)
└── documents/ # 测试文档(PDF 等)
错误消息格式标准:
Error: Radix Select 选项 "xxx" 未找到
标签: 残疾类型
期望值: xxx
可用选项: 视力残疾, 听力残疾, 肢体残疾, 智力残疾
Error: Radix Select 等待超时
标签: 省份
期望值: 广东省
超时时间: 5000ms
可能原因: 网络请求过慢或选项未加载
测试稳定性最佳实践:
waitForTimeoutdata-testid 选择器,谨慎使用文本选择器,避免使用不稳定的 CSS 类完整示例需求:
| FR 范围 | Epic | 描述 |
|---|---|---|
| FR1-FR6 | Epic 1 | Radix UI Select 测试支持(静态和异步) |
| FR7-FR24 | Epic 2 | 扩展工具集(文件上传、表单、列表、对话框) |
| FR25-FR32 | Epic 1 | 包基础设施(package.json、类型定义、配置) |
| FR33-FR40 | Epic 4 | 文档与开发者体验(README、示例、迁移指南) |
| FR41-FR45 | Epic 3 | 质量与稳定性(残疾人管理验证、稳定性测试) |
| FR46-FR50 | Epic 2 | 可扩展性设计(配置对象、版本升级兼容) |
目标: 测试开发者可以安装 @d8d/e2e-test-utils 包,立即使用 Select 工具测试 Radix UI Select 组件(最常用、最关键的测试场景)。
交付物:
selectRadixOption() 和 selectRadixOptionAsync() 函数FRs covered: FR1-FR6, FR25-FR32
用户价值:
目标: 测试开发者可以使用完整的 6 个核心工具函数,覆盖所有常见 E2E 测试场景。
交付物:
uploadFileToField() - 文件上传工具fillMultiStepForm(), scrollToSection() - 表单辅助工具addDynamicListItem(), deleteDynamicListItem() - 动态列表工具handleDialog(), waitForDialogClosed(), cancelDialog() - 对话框工具FRs covered: FR7-FR24, FR46-FR50
用户价值:
目标: 工具包在真实的残疾人管理 E2E 测试中验证,证明工具函数可用且稳定,提供完整的参考示例。
交付物:
FRs covered: FR38, FR41-FR45
用户价值:
目标: 测试开发者可以在 30 分钟内上手使用工具包,有完整的文档、示例和迁移指南。
交付物:
FRs covered: FR33-FR40
用户价值:
目标: 测试开发者可以安装 @d8d/e2e-test-utils 包,立即使用 Select 工具测试 Radix UI Select 组件(最常用、最关键的测试场景)。
作为测试开发者,
我想要可以安装 @d8d/e2e-test-utils 包,
以便在项目中使用测试工具函数。
验收标准:
Given 项目是 Monorepo 结构
When 创建 packages/e2e-test-utils/ 目录
Then 目录结构包含 src/, tests/, package.json, tsconfig.json, vitest.config.ts
And package.json 包含正确的包名、版本、peer dependencies(@playwright/test)
And tsconfig.json 启用严格模式,目标 ES2020+
And 可以通过 pnpm add -D @d8d/e2e-test-utils@workspace:* 安装
作为测试开发者, 我想要工具包有完整的类型支持和统一的错误处理, 以便获得类型安全和清晰的错误提示。
验收标准:
Given 包结构已创建
When 实现 src/types.ts, src/errors.ts, src/constants.ts
Then types.ts 导出 BaseOptions, AsyncSelectOptions, FileUploadOptions 等
And errors.ts 导出 E2ETestError 类和 ErrorContext 接口
And constants.ts 定义 DEFAULT_TIMEOUTS(static: 2000, async: 5000)
And 所有类型使用 TypeScript 严格模式,无 any 类型
作为测试开发者,
我想要使用 selectRadixOption() 函数选择静态枚举型下拉框,
以便无需理解 Radix UI DOM 结构就能编写测试。
验收标准:
Given 类型定义已创建
When 实现 src/radix-select.ts 中的 selectRadixOption() 函数
Then 函数签名:selectRadixOption(page: Page, label: string, value: string): Promise<void>
And 选择器策略:data-testid → aria-label + role → text content
And 自动处理点击触发器、等待选项列表、点击选项
And 错误时抛出 E2ETestError,包含标签、期望值、可用选项
And 操作在 2 秒内完成(NFR8)
作为测试开发者,
我想要使用 selectRadixOptionAsync() 函数选择异步加载的下拉框,
以便测试省份、城市等动态加载的选项。
验收标准:
Given 静态 Select 函数已实现
When 实现 selectRadixOptionAsync(page, label, value, options?) 函数
Then 支持 AsyncSelectOptions 配置(timeout, waitForOption)
And 使用 waitForLoadState('networkidle') 等待异步加载
And 默认超时 5 秒,可配置
And 超时时提供清晰错误消息(标签、期望值、超时时间、可能原因)
作为测试开发者, 我想要可以导入工具函数并查看快速入门文档, 以便快速开始使用工具包。
验收标准:
Given Select 工具函数已实现
When 创建 src/index.ts 和 README.md
Then index.ts 导出所有公共函数和类型(tree-shakeable)
And README 包含:安装说明、快速入门、Select 使用示例
And 所有导出函数有完整的 JSDoc 注释
And 可以 import { selectRadixOption } from '@d8d/e2e-test-utils'
作为测试开发者, 我想要 Select 工具函数有充分的单元测试, 以便确保函数的正确性和稳定性。
验收标准:
Given Select 工具函数已实现
When 创建 tests/unit/radix-select.test.ts
Then 测试覆盖率 ≥ 80%(NFR29)
And 测试用例包括:成功选择、选项不存在、超时、错误处理
And 使用 Vitest 运行测试
And 所有测试通过
目标: 测试开发者可以使用完整的 6 个核心工具函数,覆盖所有常见 E2E 测试场景。
作为测试开发者,
我想要使用 uploadFileToField() 函数上传文件,
以便测试照片上传、文档上传等功能。
验收标准:
Given Epic 1 的类型定义已存在
When 实现 src/file-upload.ts 中的 uploadFileToField(page, selector, fileName) 函数
Then 函数从 fixtures 目录加载测试文件
And 使用 Playwright 的 setInputFiles() API
And 支持相对路径(相对于 fixtures 目录)
And 错误时提供清晰消息(文件路径、选择器、失败原因)
And 操作在 5 秒内完成(NFR9)
作为测试开发者,
我想要使用 fillMultiStepForm() 和 scrollToSection() 函数,
以便测试多步骤表单和滚动操作。
验收标准:
Given 类型定义已存在
When 实现 src/form-helper.ts 中的表单辅助函数
Then fillMultiStepForm(page, steps) 支持分步填写表单
And scrollToSection(page, sectionName) 滚动到特定区域
And 支持常见字段类型(文本、选择器、日期等)
And 自动处理表单验证错误场景
作为测试开发者,
我想要使用 addDynamicListItem() 和 deleteDynamicListItem() 函数,
以便测试银行卡管理、备注管理等动态列表功能。
验收标准:
Given 类型定义已存在
When 实现 src/dynamic-list.ts 中的动态列表函数
Then addDynamicListItem(page, itemType, data) 添加新列表项
And deleteDynamicListItem(page, itemType, index) 删除指定索引的项
And 支持不同类型列表项(银行卡、备注等)
And 验证列表状态变化
And 处理异步更新场景
作为测试开发者,
我想要使用 handleDialog(), waitForDialogClosed(), cancelDialog() 函数,
以便统一操作 Radix UI Dialog。
验收标准:
Given 类型定义已存在
When 实现 src/dialog.ts 中的对话框操作函数
Then handleDialog(page, action) 支持 confirm/cancel/close 操作
And waitForDialogClosed(page) 等待对话框完全关闭
And cancelDialog(page) 提供取消操作的快捷方式
And 理解 Radix UI Dialog 的 DOM 结构(role="dialog")
And 等待对话框关闭后再继续后续操作
作为测试开发者, 我想要可以导入所有新增的工具函数, 并参考 Fixtures 目录结构示例。
验收标准:
Given 所有扩展工具函数已实现
When 更新 src/index.ts 和创建 Fixtures 目录示例
Then index.ts 导出所有新函数(uploadFileToField, fillMultiStepForm 等)
And 创建 tests/fixtures/ 目录结构示例
And Fixtures 包含 images/ 和 documents/ 子目录
And 提供示例测试文件(sample-id-card.jpg 等)
And 所有函数有完整的 JSDoc 注释
作为测试开发者, 我想要所有扩展工具函数有充分的单元测试, 以便确保函数的正确性和稳定性。
验收标准:
Given 扩展工具函数已实现
When 创建 tests/unit/ 下的测试文件
Then 测试覆盖率 ≥ 80%(NFR29)
And 测试文件包括:file-upload.test.ts, form-helper.test.ts, dynamic-list.test.ts, dialog.test.ts
And 每个函数的成功和失败场景都有测试
And 使用 Vitest 运行,所有测试通过
目标: 工具包在真实的残疾人管理 E2E 测试中验证,证明工具函数可用且稳定,提供完整的参考示例。
作为测试开发者, 我想要有一个独立的测试应用来验证工具函数, 以便在真实环境中测试工具包的集成。
验收标准:
Given Epic 1-2 的工具函数已实现
When 创建 tests/test-app/ 独立测试应用
Then 测试应用使用 Vite + React
And 包含 Radix UI 组件页面(Select、Dialog、File Upload、Form、Dynamic List)
And Playwright 配置自动启动测试应用服务器
And 可以通过 pnpm test 运行集成测试
作为测试开发者, 我想要使用工具函数测试残疾人管理的照片上传功能, 以便验证文件上传工具的可用性。
验收标准:
Given 测试基础设施已创建
When 编写照片上传 E2E 测试
Then 使用 uploadFileToField() 上传身份证照片
And 使用 uploadFileToField() 上传残疾证照片
And 验证文件上传成功
And 测试覆盖多文件上传场景
And 测试使用 fixtures 中的示例文件
作为测试开发者, 我想要使用工具函数测试残疾人管理的银行卡管理功能, 以便验证动态列表和对话框工具的可用性。
验收标准:
Given 测试基础设施已创建
When 编写银行卡管理 E2E 测试
Then 使用 handleDialog() 打开添加银行卡对话框
And 填写银行卡信息(银行名称、卡号、持卡人)
And 使用 addDynamicListItem() 添加银行卡
And 使用 deleteDynamicListItem() 删除银行卡
And 验证列表状态变化
作为测试开发者, 我想要使用工具函数测试残疾人管理的备注和回访功能, 以便验证表单和动态列表工具的综合使用。
验收标准:
Given 测试基础设施已创建
When 编写备注和回访 E2E 测试
Then 使用 fillMultiStepForm() 填写备注表单
And 使用 scrollToSection() 滚动到回访区域
And 使用 addDynamicListItem() 添加备注
And 验证表单提交和列表更新
作为测试开发者, 我想要有一个完整的残疾人管理流程测试, 以便演示所有工具函数的综合使用。
验收标准:
Given 各功能测试已完成
When 编写完整流程 E2E 测试
Then 测试包含:基本信息填写(使用 selectRadixOption 选择静态和异步 Select)
And 照片上传(使用 uploadFileToField)
And 银行卡管理(使用 handleDialog, addDynamicListItem)
And 备注添加(使用 fillMultiStepForm)
And 表单提交和验证
And 演示与 Page Object 模式的集成
作为测试开发者, 我想要有稳定性测试验证工具包的可靠性, 以便确保工具函数连续运行 20 次 100% 通过。
验收标准:
Given 完整流程测试已编写
When 创建 tests/stability/repeat-run.spec.ts
Then 测试连续运行 20 次完整流程
And 验证 100% 通过率(NFR1)
And 测试执行时间符合性能标准(NFR8-NFR11)
And 无 flaky 失败
And 使用 Playwright 运行稳定性测试
目标: 测试开发者可以在 30 分钟内上手使用工具包,有完整的文档、示例和迁移指南。
作为测试开发者, 我想要有完整的 README 和 API 文档, 以便快速上手使用工具包。
验收标准:
Given Epic 1-3 的所有功能已实现
When 完善 README.md 和 API 文档
Then README 包含:项目简介、安装说明、快速入门、API 文档
And 每个工具函数都有完整的使用示例
And 说明静态 Select 和异步 Select 的区别和使用场景
And 包含迁移指南(从现有测试代码到工具函数)
And 包含常见问题和解决方案
And 残疾人管理测试作为完整示例
And 所有函数有完整的 JSDoc 注释