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 测试支持(静态和异步) |
| FR25-FR32 | Epic 1 | 包基础设施(package.json、类型定义、配置) |
| FR7-FR24, FR46-FR50 | Epic 3 | 扩展工具集(文件上传、表单、列表、对话框、可扩展性) |
| FR41-FR45 | Epic 2 & 4 | 质量与稳定性(Select 验证、全面验证、稳定性测试) |
| FR33-FR40 | Epic 5 | 文档与开发者体验(README、示例、迁移指南) |
Epic 规划变更说明(2026-01-09):
目标: 测试开发者可以安装 @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 所有测试通过
目标: 在 web/tests/e2e/ 的现有残疾人管理测试中使用 Select 工具,验证工具在真实场景中的可用性和稳定性,收集实际使用反馈,为后续工具设计提供指导。
背景: Epic 1 已完成 Select 工具的开发和单元测试,但尚未在真实 E2E 测试场景中验证。通过在现有测试中使用这些工具,我们可以:
范围:
web/tests/e2e/ 测试基础设施依赖:
验收标准:
作为测试开发者,
我想要在 web 目录安装 @d8d/e2e-test-utils 包,
以便在 E2E 测试中使用 Select 工具。
验收标准:
Given Epic 1 已完成,@d8d/e2e-test-utils 包已构建
When 在 web/package.json 中添加 workspace 依赖
Then 可以在 web/tests/e2e/ 中导入 Select 工具
And TypeScript 类型检查通过
And 运行时无依赖错误
实现要点:
pnpm add -D @d8d/e2e-test-utils@workspace:* 安装web/tests/e2e/ 中可以导入:import { selectRadixOption } from '@d8d/e2e-test-utils'作为测试开发者,
我想要使用 selectRadixOption() 替换 Page Object 中的 Select 操作,
以便验证工具在静态 Select 场景中的可用性。
验收标准:
Given @d8d/e2e-test-utils 已安装
When 修改 web/tests/e2e/pages/admin/disability-person.page.ts
Then fillBasicForm() 中的残疾类型选择使用 selectRadixOption()
And fillBasicForm() 中的残疾等级选择使用 selectRadixOption()
And 移除原有的 selectRadixOption() 方法
And 测试通过,功能正常
验证场景:
作为测试开发者,
我想要使用 selectRadixOptionAsync() 处理异步加载的 Select,
以便验证工具在异步 Select 场景中的可用性。
验收标准:
Given @d8d/e2e-test-utils 已安装
When 修改 web/tests/e2e/pages/admin/disability-person.page.ts
Then fillBasicForm() 中的省份选择使用 selectRadixOptionAsync()
And fillBasicForm() 中的城市选择使用 selectRadixOptionAsync()
And 移除 waitForTimeout(500) 等待城市加载的 hack
And 测试通过,功能正常
验证场景:
配置要点:
waitForOption: true 等待选项加载作为测试开发者, 我想要运行使用新工具的测试并收集反馈, 以便发现潜在问题并改进工具。
验收标准:
web/tests/e2e/specs/admin/disability-person-complete.spec.ts关注点:
作为测试开发者, 我想要修复 Story 2.4 中发现的问题, 以便工具可以正常使用。
验收标准:
优先级:
作为测试开发者, 我想要验证测试的稳定性, 以便确保工具可以可靠地使用。
验收标准:
Given 所有问题已修复 When 连续运行测试 10 次 Then 所有测试 100% 通过 And 无 flaky 失败 And 平均执行时间 < 5 分钟
测试场景:
pnpm test:e2e:chromium disability-person-complete.spec.ts 运行 10 次成功标准:
目标: 测试开发者可以使用完整的 6 个核心工具函数,覆盖所有常见 E2E 测试场景。
说明: 本 Epic 原 Epic 2,已在 Epic 2 完成后重新编号。
作为测试开发者,
我想要使用 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 测试中验证,证明工具函数可用且稳定,提供完整的参考示例。
说明: 本 Epic 原 Epic 3,已在 Epic 2 完成后重新编号。
注意: 原 Epic 3 的范围需要调整,因为 Epic 2 已涵盖 Select 工具的验证。
作为测试开发者,
我想要在现有的残疾人管理 E2E 测试中使用文件上传工具,
以便验证 uploadFileToField() 的可用性。
验收标准:
Given Epic 3 已完成,文件上传工具已实现
When 在 web/tests/e2e/specs/admin/disability-person-complete.spec.ts 中使用 uploadFileToField()
Then 上传身份证照片(正面、反面)
And 上传残疾证照片
And 验证文件上传成功
And 测试使用 web/tests/e2e/fixtures/images/ 中的示例文件
作为测试开发者, 我想要在现有的残疾人管理 E2E 测试中使用动态列表和对话框工具, 以便验证这些工具的可用性。
验收标准:
Given Epic 3 已完成,对话框和动态列表工具已实现
When 在现有测试中使用 handleDialog(), addDynamicListItem(), deleteDynamicListItem()
Then 打开添加银行卡对话框
And 填写银行卡信息(银行名称、卡号、持卡人)
And 添加银行卡到列表
And 验证列表状态变化
作为测试开发者, 我想要在现有的残疾人管理 E2E 测试中使用表单辅助工具, 以便验证表单工具的综合使用。
验收标准:
Given Epic 3 已完成,表单辅助工具已实现
When 在现有测试中使用 fillMultiStepForm(), scrollToSection()
Then 填写备注表单
And 滚动到回访区域
And 添加备注到列表
And 验证表单提交和列表更新
作为测试开发者, 我想要在现有的完整流程测试中使用所有工具, 以便演示所有工具函数的综合使用。
验收标准:
Given Epic 2-4 的所有工具已在部分测试中验证
When 确保 disability-person-complete.spec.ts 使用所有工具
Then 基本信息:使用 selectRadixOption 和 selectRadixOptionAsync
And 照片上传:使用 uploadFileToField
And 银行卡管理:使用 handleDialog, addDynamicListItem, deleteDynamicListItem
And 备注添加:使用 fillMultiStepForm, scrollToSection, addDynamicListItem
And 所有测试通过
作为测试开发者, 我想要有稳定性测试验证工具包的可靠性, 以便确保工具函数连续运行 20 次 100% 通过。
验收标准:
Given 完整流程测试已编写
When 创建 tests/stability/repeat-run.spec.ts
Then 测试连续运行 20 次完整流程
And 验证 100% 通过率(NFR1)
And 测试执行时间符合性能标准(NFR8-NFR11)
And 无 flaky 失败
And 使用 Playwright 运行稳定性测试
目标: 测试开发者可以在 30 分钟内上手使用工具包,有完整的文档、示例和迁移指南。
说明: 本 Epic 原 Epic 4,已在 Epic 2 完成后重新编号。
作为测试开发者, 我想要有完整的 README 和 API 文档, 以便快速上手使用工具包。
验收标准:
Given Epic 1-4 的所有功能已实现
When 完善 README.md 和 API 文档
Then README 包含:项目简介、安装说明、快速入门、API 文档
And 每个工具函数都有完整的使用示例
And 说明静态 Select 和异步 Select 的区别和使用场景
And 包含迁移指南(从现有测试代码到工具函数)
And 包含常见问题和解决方案
And 残疾人管理测试作为完整示例
And 所有函数有完整的 JSDoc 注释