epics.md 50 KB


stepsCompleted: ['step-01-validate-prerequisites', 'step-02-design-epics', 'step-03-create-stories', 'step-04-final-validation', 'revision-2025-01-10', 'step-01-revalidate-2025-01-10'] inputDocuments:

  • name: PRD - Web E2E 测试覆盖 path: _bmad-output/planning-artifacts/prd.md type: prd loadedAt: '2026-01-10T11:30:00.000Z'
  • name: Architecture Decision Document path: _bmad-output/planning-artifacts/architecture.md type: architecture loadedAt: '2026-01-08T02:10:00.000Z' revisedAt: '2026-01-10' revisionNotes: '修订范围:根据修订后的 PRD,从"E2E测试工具包开发"更新为"Web E2E 测试覆盖",业务测试为主,工具包为支持手段' ---

188-179-template-6 - Epic Breakdown

Overview

本文档提供了 188-179-template-6 的完整 Epic 和 Story 分解,将 PRD 和 Architecture 要求分解为可实现的 Story。

项目定位(修订后): 为 Web 管理后台的业务功能建立完整的 E2E 测试覆盖,在测试过程中将通用模式抽象到 @d8d/e2e-test-utils 包中。

Epic 组织:

  • Epic A: 残疾人管理 E2E 测试 ✅ 已完成
  • Epic B: 区域管理 E2E 测试 🔄 当前目标
  • Epic C: e2e-test-utils 包维护 🌟 支持性任务

Requirements Inventory

Functional Requirements

Radix UI Select 组件测试支持 (FR1-FR6):

  • FR1: 测试开发者可以使用工具函数选择静态枚举型 Radix UI Select 下拉框的选项
  • FR2: 测试开发者可以使用工具函数选择异步加载型 Radix UI Select 下拉框的选项
  • FR3: 工具函数可以自动处理 Radix UI Select 的 DOM 结构和交互流程
  • FR4: 工具函数可以等待异步加载的选项出现在下拉列表中
  • FR5: 工具函数可以提供清晰的错误提示,包含标签、期望值等上下文信息
  • FR6: 工具函数可以区分"元素未找到"和"超时"错误类型

文件上传测试支持 (FR7-FR10):

  • FR7: 测试开发者可以使用工具函数上传文件到指定的文件输入字段
  • FR8: 工具函数可以从 fixtures 目录加载测试文件
  • FR9: 工具函数可以支持多文件上传场景
  • FR10: 工具函数可以验证文件上传是否成功完成

表单交互测试支持 (FR11-FR15):

  • FR11: 测试开发者可以使用工具函数填写多步骤表单
  • FR12: 工具函数可以滚动页面到特定的表单区域
  • FR13: 工具函数可以处理表单验证错误场景
  • FR14: 测试开发者可以使用工具函数提交表单并等待响应
  • FR15: 工具函数可以支持常见的表单字段类型(文本、选择器、日期等)

动态列表测试支持 (FR16-FR20):

  • FR16: 测试开发者可以使用工具函数向动态列表中添加新项
  • FR17: 测试开发者可以使用工具函数从动态列表中删除项
  • FR18: 工具函数可以支持不同类型的动态列表项(银行卡、备注等)
  • FR19: 工具函数可以验证动态列表项添加或删除后的状态
  • FR20: 工具函数可以处理动态列表的异步更新场景

对话框操作测试支持 (FR21-FR24):

  • FR21: 测试开发者可以使用工具函数统一操作对话框(确认、取消、关闭)
  • FR22: 工具函数可以等待对话框完全关闭后再继续执行
  • FR23: 工具函数可以处理对话框内的表单填写和提交
  • FR24: 工具函数可以验证对话框是否按预期打开或关闭

测试工具包基础设施 (FR25-FR32):

  • FR25: 测试开发者可以通过 npm workspace 协议安装测试工具包
  • FR26: 工具包可以作为 peer dependency 依赖 Playwright,不增加运行时依赖
  • FR27: 工具包提供完整的 TypeScript 类型定义和类型提示
  • FR28: 工具包的所有导出函数都有完整的 JSDoc 注释
  • FR29: 工具包使用严格类型检查,不使用 any 类型
  • FR30: 工具包支持目标 ES2020+ 的 JavaScript 环境
  • FR31: 工具包的每个工具函数都可以独立导入和使用
  • FR32: 工具包可以与其他测试工具和库兼容使用

文档和开发者支持 (FR33-FR40):

  • FR33: 测试开发者可以通过 README 快速了解工具包的用途和安装方法
  • FR34: 文档提供每个工具函数的详细使用示例
  • FR35: 文档提供静态 Select 和异步 Select 的区别说明
  • FR36: 文档提供从现有测试代码迁移到工具函数的指南
  • FR37: 文档提供常见问题和解决方案
  • FR38: 文档提供残疾人管理测试作为完整的使用示例
  • FR39: 测试开发者可以在 30 分钟内使用工具函数编写第一个测试
  • FR40: 工具包的使用示例覆盖所有 6 个核心工具函数

测试质量和稳定性保障 (FR41-FR45):

  • FR41: 工具函数使用 Playwright 的 auto-waiting 机制防止时序问题
  • FR42: 工具函数为静态选项设置合理的默认超时配置
  • FR43: 工具函数为异步选项提供可配置的超时参数
  • FR44: 工具函数可以支持重试机制处理不稳定的网络请求
  • FR45: 工具函数可以在测试连续运行 20 次时保持 100% 通过率

可扩展性和维护性 (FR46-FR50):

  • FR46: 工具函数支持配置对象参数,允许自定义行为
  • FR47: 工具函数设计支持未来的 Radix UI 版本升级
  • FR48: 工具函数使用稳定的选择器策略(role、data-testid)
  • FR49: 工具包预留扩展接口,支持新增其他 Radix 组件测试模式
  • FR50: 工具包的代码结构清晰,便于团队贡献和维护

NonFunctional Requirements

可靠性 (NFR1-NFR7):

  • NFR1: 工具函数在相同条件下连续运行 20 次,必须保持 100% 通过率,无 flaky 失败
  • NFR2: 工具函数能够正确处理异步加载场景,避免时序问题导致的测试失败
  • NFR3: 当 DOM 元素暂时不可用时,工具函数提供清晰的错误消息,而不是超时无响应
  • NFR4: 工具函数能够区分产品 bug 和测试代码问题,帮助开发者快速定位问题根源
  • NFR5: 当选择操作失败时,错误消息包含:下拉框标签名称、期望选择的值、实际可用的选项列表、失败原因
  • NFR6: 当文件上传失败时,错误消息包含文件路径、选择器、失败原因
  • NFR7: 错误消息格式统一,便于日志分析和问题定位

性能 (NFR8-NFR14):

  • NFR8: 单个 Radix UI Select 选择操作(静态)应在 2 秒内完成
  • NFR9: 单个 Radix UI Select 选择操作(异步)应在 5 秒内完成(默认超时)
  • NFR10: 工具函数本身的开销不超过 100ms(不包括 Playwright 操作时间)
  • NFR11: 使用工具函数的测试比手动编写 DOM 操作的测试执行时间差异 < 10%
  • NFR12: 静态选项使用合理的默认超时(2 秒),避免不必要的等待
  • NFR13: 异步选项提供可配置的超时参数,默认值为 5 秒
  • NFR14: 工具函数使用 Playwright 的 auto-waiting 机制,减少显式等待的需要

集成性 (NFR15-NFR24):

  • NFR15: 工具包兼容 Playwright 最新稳定版本和上一个 LTS 版本
  • NFR16: 工具包可以作为 peer dependency 引用,不增加运行时依赖
  • NFR17: 工具函数接受标准 Playwright Page 对象作为参数
  • NFR18: 工具包不依赖特定版本的 Playwright,使用灵活的版本范围
  • NFR19: 工具函数可以在任何使用 Playwright 的测试框架中运行(Vitest、Jest 等)
  • NFR20: 工具包不修改全局配置,不需要额外的测试框架配置
  • NFR21: 工具函数可以与现有的 Page Object 模式无缝集成
  • NFR22: 工具包通过 pnpm workspace 协议安装,支持本地开发
  • NFR23: 工具包的构建产物与项目的 TypeScript 配置兼容
  • NFR24: 工具包的类型定义可以自动被 IDE 识别和提示

代码质量 (NFR25-NFR40):

  • 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-NFR46):

  • NFR41: 工具函数在 Playwright 支持的所有浏览器中正常工作(Chromium、Firefox、WebKit)
  • NFR42: 工具函数在 headless 和 headed 模式下都能正常工作
  • NFR43: 工具函数在 CI/CD 环境中稳定运行
  • NFR44: 工具包支持 Node.js 当前 LTS 版本和上一个 LTS 版本
  • NFR45: 工具包的设计考虑未来 Radix UI 版本升级,使用稳定的选择器策略
  • NFR46: 重大版本变更时提供迁移指南

Additional Requirements

从 Architecture 文档提取的技术需求:

包结构需求:

  • 创建独立包 packages/e2e-test-utils,与现有的 @d8d/shared-test-util(后端集成测试)分离
  • 按功能分组文件结构:src/ 分为 radix-select.ts, file-upload.ts, form-helper.ts, dialog.ts, dynamic-list.ts
  • 共享代码集中在 types.ts, errors.ts, constants.ts
  • 主导出使用 index.ts,支持 tree-shaking

API 设计需求:

  • 必需参数 ≤ 3 个,复杂配置通过可选对象传递
  • 函数命名:动词+名词,camelCase(如 selectRadixOption
  • 异步函数添加 Async 后缀(如 selectRadixOptionAsync
  • 类型命名:接口 PascalCase + Options 后缀(如 AsyncSelectOptions

类型系统需求:

  • 分层类型:types.ts 存放共享类型(BaseOptions),各模块文件存放特定类型
  • 所有配置对象继承 BaseOptions
  • TypeScript 严格模式,无 any 类型

选择器策略需求:

  • 混合策略优先级:data-testid → aria-label + role → text content + role
  • 推荐在 Radix 组件上添加 data-testid

错误处理需求:

  • 使用结构化错误类 E2ETestError + ErrorContext
  • 错误消息格式:❌ 操作失败、上下文信息、💡 修复建议

测试策略需求:

  • 三层测试:单元测试(Vitest)、集成测试(Playwright)、稳定性测试(20次连续运行)
  • 创建独立测试应用 tests/test-app/ 使用 Vite + React
  • 测试应用提供真实的 @d8d/shared-ui-components 组件
  • Playwright 配置自动启动测试应用服务器
  • 单元测试覆盖率 ≥ 80%

常量定义需求:

  • 超时常量:DEFAULT_TIMEOUTS.static = 2000, async = 5000, networkIdle = 10000
  • 选择器策略常量:SELECTOR_STRATEGIES 数组

文档需求:

  • 完整的 JSDoc 注释格式
  • README 包含快速入门、安装说明、基本用法
  • 每个工具函数至少有 1 个实际使用示例
  • 迁移指南:从现有测试代码迁移到工具函数

遵循项目标准:

  • 遵循 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 结构理解需求:

  • 理解 Radix UI Select 的典型 DOM 结构:data-radix-select-trigger 触发器,role="listbox" 选项列表,role="option" 单个选项
  • 理解 Radix UI Dialog 的 DOM 结构: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
  可能原因: 网络请求过慢或选项未加载

测试稳定性最佳实践:

  • 使用 Playwright 的 auto-waiting 机制,不使用 waitForTimeout
  • 优先使用 data-testid 选择器,谨慎使用文本选择器,避免使用不稳定的 CSS 类
  • 测试隔离:每个测试前清理数据,失败时截图
  • 明确的错误断言:使用具体的选择器和期望的文本内容

完整示例需求:

  • 提供残疾人管理 E2E 测试作为完整示例
  • 演示静态 Select、异步 Select、文件上传、动态列表、对话框的综合使用
  • 展示与 Page Object 模式的集成方式

FR Coverage Map

FR 范围 Epic 描述
FR1-FR6 Epic 1 Radix UI Select 测试支持(静态和异步)
FR25-FR32 Epic 1 包基础设施(package.json、类型定义、配置)
FR7-FR10 Epic 3 文件上传测试支持(文件上传工具与验证)
FR11-FR15 Epic 4 表单交互测试支持(表单工具与验证)
FR16-FR24 Epic 5 列表和对话框测试支持(列表和对话框工具与验证)
FR41-FR45 Epic 2, 3, 4, 5, 6, 8 质量与稳定性(各工具验证、全面验证、稳定性测试)
FR33-FR40 Epic 7 文档与开发者体验(README、示例、迁移指南)
FR46-FR50 Epic 3, 4, 5, 8 可扩展性(各工具的配置和扩展支持)
FR1-FR50 Epic 8 区域管理 E2E 测试(复用现有工具,必要时扩展级联选择/树形结构工具)

Epic 规划变更说明(2026-01-10):

  • Epic 1: ✅ 已完成(Select 工具基础框架)
  • Epic 2: ✅ 已完成(在现有 E2E 测试中验证 Select 工具)
  • Epic 3: 🆕 文件上传工具开发与验证(遵循 Epic 2 成功模式)
  • Epic 4: 🆕 表单工具开发与验证(遵循 Epic 2 成功模式)
  • Epic 5: 🆕 列表和对话框工具开发与验证(遵循 Epic 2 成功模式)
  • Epic 6: 完整验证(残疾人管理)
  • Epic 7: 文档与开发者体验
  • Epic 8: 🆕 区域管理 E2E 测试 (Epic B - 业务测试 Epic)

"先验证再扩展"策略: 基于 Epic 2 的成功经验,每个工具都遵循"开发 → E2E 验证 → 稳定性验证"的模式:

  • Epic 3: 文件上传工具(优先解决当前测试超时问题)
  • Epic 4: 表单工具
  • Epic 5: 列表和对话框工具

Epic List

Epic 1: 测试工具包基础框架与 Select 支持

目标: 测试开发者可以安装 @d8d/e2e-test-utils 包,立即使用 Select 工具测试 Radix UI Select 组件(最常用、最关键的测试场景)。

状态: ✅ Done

交付物:

  • 完整的包结构和配置(package.json, tsconfig.json, vitest.config.ts)
  • selectRadixOption()selectRadixOptionAsync() 函数
  • 类型定义和错误处理(E2ETestError, ErrorContext)
  • 选择器策略实现(testid → ARIA → text)
  • 基础文档(README 安装、快速入门)
  • 单元测试(Vitest)

FRs covered: FR1-FR6, FR25-FR32


Epic 2: 在现有 E2E 测试中验证 Select 工具

目标:web/tests/e2e/ 的残疾人管理测试中使用 Select 工具,验证工具在真实场景中的可用性和稳定性。

状态: ✅ Done

交付物:

  • Select 工具在残疾人管理测试中的实际应用
  • 5 处静态 Select 迁移(残疾类型、等级等)
  • 2 处异步 Select 迁移(省份、城市)
  • DOM 结构问题修复(listbox → option)

FRs covered: FR41-FR45 (部分)

关键经验:

  • DOM 结构假设必须验证
  • 真实 E2E 测试不可替代
  • "先验证再扩展"策略有效

Epic 3: 文件上传工具开发与验证

目标: 遵循 Epic 2 成功模式,开发文件上传工具并在真实 E2E 测试中验证,解决当前测试超时阻塞问题。

状态: 🆕 Backlog

模式: 工具开发 → 真实 E2E 测试验证 → 问题修复 → 稳定性验证

交付物:

  • uploadFileToField() 文件上传工具
  • 单元测试(Vitest)
  • 在残疾人管理测试中验证(至少 3 处文件上传)
  • 稳定性验证(10次连续运行)

FRs covered: FR7-FR10, FR46-FR50 (部分), FR41-FR45 (部分)


Epic 4: 表单工具开发与验证

目标: 开发表单辅助工具并在真实 E2E 测试中验证。

状态: Backlog (等待 Epic 3 完成)

模式: 工具开发 → 真实 E2E 测试验证 → 稳定性验证

交付物:

  • fillMultiStepForm(), scrollToSection() - 表单辅助工具
  • 单元测试
  • 在残疾人管理测试中验证
  • 稳定性验证

FRs covered: FR11-FR15, FR46-FR50 (部分), FR41-FR45 (部分)


Epic 5: 列表和对话框工具开发与验证

目标: 开发动态列表和对话框工具并在真实 E2E 测试中验证。

状态: Backlog (等待 Epic 4 完成)

模式: 工具开发 → 真实 E2E 测试验证 → 稳定性验证

交付物:

  • addDynamicListItem(), deleteDynamicListItem() - 动态列表工具
  • handleDialog(), waitForDialogClosed() - 对话框工具
  • 单元测试
  • 在残疾人管理测试中验证
  • 稳定性验证

FRs covered: FR16-FR24, FR46-FR50 (部分), FR41-FR45 (部分)


Epic 6: 完整验证(残疾人管理)

目标: 工具包在真实的残疾人管理 E2E 测试中完整验证,证明所有工具函数可用且稳定。

状态: Backlog (等待 Epic 5 完成)

交付物:

  • 残疾人管理完整流程测试(使用所有工具)
  • 稳定性验证(20次连续运行 100% 通过)

FRs covered: FR38, FR41-FR45


Epic 7: 完善文档与开发者体验

目标: 测试开发者可以在 30 分钟内上手使用工具包,有完整的文档、示例和迁移指南。

状态: Backlog (等待 Epic 6 完成)

交付物:

  • 完整的 README(安装、快速入门、API 文档)
  • VS Code snippets
  • 迁移指南

FRs covered: FR33-FR40


Epic 1: 测试工具包基础框架与 Select 支持

目标: 测试开发者可以安装 @d8d/e2e-test-utils 包,立即使用 Select 工具测试 Radix UI Select 组件(最常用、最关键的测试场景)。


Story 1.1: 创建包基础结构和配置

作为测试开发者, 我想要可以安装 @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/testAnd tsconfig.json 启用严格模式,目标 ES2020+ And 可以通过 pnpm add -D @d8d/e2e-test-utils@workspace:* 安装


Story 1.2: 实现类型定义和错误处理

作为测试开发者, 我想要工具包有完整的类型支持和统一的错误处理, 以便获得类型安全和清晰的错误提示。

验收标准:

Given 包结构已创建 When 实现 src/types.ts, src/errors.ts, src/constants.ts Then types.ts 导出 BaseOptions, AsyncSelectOptions, FileUploadOptionsAnd errors.ts 导出 E2ETestError 类和 ErrorContext 接口 And constants.ts 定义 DEFAULT_TIMEOUTS(static: 2000, async: 5000) And 所有类型使用 TypeScript 严格模式,无 any 类型


Story 1.3: 实现静态 Select 工具函数

作为测试开发者, 我想要使用 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)


Story 1.4: 实现异步 Select 工具函数

作为测试开发者, 我想要使用 selectRadixOptionAsync() 函数选择异步加载的下拉框, 以便测试省份、城市等动态加载的选项。

验收标准:

Given 静态 Select 函数已实现 When 实现 selectRadixOptionAsync(page, label, value, options?) 函数 Then 支持 AsyncSelectOptions 配置(timeout, waitForOption) And 使用 waitForLoadState('networkidle') 等待异步加载 And 默认超时 5 秒,可配置 And 超时时提供清晰错误消息(标签、期望值、超时时间、可能原因)


Story 1.5: 创建主导出和基础文档

作为测试开发者, 我想要可以导入工具函数并查看快速入门文档, 以便快速开始使用工具包。

验收标准:

Given Select 工具函数已实现 When 创建 src/index.tsREADME.md Then index.ts 导出所有公共函数和类型(tree-shakeable) And README 包含:安装说明、快速入门、Select 使用示例 And 所有导出函数有完整的 JSDoc 注释 And 可以 import { selectRadixOption } from '@d8d/e2e-test-utils'


Story 1.6: Select 工具函数单元测试

作为测试开发者, 我想要 Select 工具函数有充分的单元测试, 以便确保函数的正确性和稳定性。

验收标准:

Given Select 工具函数已实现 When 创建 tests/unit/radix-select.test.ts Then 测试覆盖率 ≥ 80%(NFR29) And 测试用例包括:成功选择、选项不存在、超时、错误处理 And 使用 Vitest 运行测试 And 所有测试通过


Epic 2: 在现有 E2E 测试中验证 Select 工具

目标:web/tests/e2e/ 的现有残疾人管理测试中使用 Select 工具,验证工具在真实场景中的可用性和稳定性,收集实际使用反馈,为后续工具设计提供指导。

背景: Epic 1 已完成 Select 工具的开发和单元测试,但尚未在真实 E2E 测试场景中验证。通过在现有测试中使用这些工具,我们可以:

  1. 验证工具在实际业务场景中的可用性
  2. 发现并修复潜在问题
  3. 收集使用体验反馈,改进 API 设计
  4. 为后续工具开发建立信心和经验

范围:

  • ✅ 使用现有 web/tests/e2e/ 测试基础设施
  • ✅ 使用现有的残疾人管理测试场景
  • ✅ 替换 Page Object 中现有的 Select 操作
  • ❌ 不创建新的测试应用
  • ❌ 不添加新功能(仅验证现有功能)

依赖:

  • Epic 1: ✅ 已完成(Select 工具已开发)

验收标准:

  1. Select 工具在至少 2 个真实 E2E 测试场景中使用
  2. 所有测试连续运行 10 次,100% 通过率
  3. 发现的问题已记录并修复(或列入待办)
  4. 收集的使用反馈已整理

Story 2.1: 在 web 目录安装 @d8d/e2e-test-utils

作为测试开发者, 我想要在 web 目录安装 @d8d/e2e-test-utils 包, 以便在 E2E 测试中使用 Select 工具。

验收标准:

Given Epic 1 已完成,@d8d/e2e-test-utils 包已构建 Whenweb/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'

Story 2.2: 使用 selectRadixOption 重写残疾类型选择

作为测试开发者, 我想要使用 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 测试通过,功能正常

验证场景:

  • 残疾类型:视力残疾、听力残疾、肢体残疾、言语残疾等(静态选项)
  • 残疾等级:一级、二级、三级、四级(静态选项)

Story 2.3: 使用 selectRadixOptionAsync 重写省份/城市选择

作为测试开发者, 我想要使用 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 等待选项加载
  • 使用合理的超时配置(5-10 秒)

Story 2.4: 运行测试并收集问题和改进建议

作为测试开发者, 我想要运行使用新工具的测试并收集反馈, 以便发现潜在问题并改进工具。

验收标准:

  1. 运行 web/tests/e2e/specs/admin/disability-person-complete.spec.ts
  2. 记录所有问题(包括失败的测试、错误消息、使用体验)
  3. 分类问题:工具 bug vs 使用错误 vs 改进建议
  4. 整理成问题清单

关注点:

  • 工具是否按预期工作?
  • 错误消息是否清晰?
  • API 是否简洁易用?
  • 是否有性能问题?

Story 2.5: 修复发现的问题

作为测试开发者, 我想要修复 Story 2.4 中发现的问题, 以便工具可以正常使用。

验收标准:

  • 所有标记为"工具 bug"的问题已修复
  • 所有测试通过
  • 修复已记录到 story 文件

优先级:

  • HIGH: 影响测试结果的问题(如选择失败、超时)
  • MEDIUM: 影响开发体验的问题(如错误消息不清晰)
  • LOW: 优化建议(如性能改进)

Story 2.6: 稳定性验证

作为测试开发者, 我想要验证测试的稳定性, 以便确保工具可以可靠地使用。

验收标准:

Given 所有问题已修复 When 连续运行测试 10 次 Then 所有测试 100% 通过 And 无 flaky 失败 And 平均执行时间 < 5 分钟

测试场景:

  • pnpm test:e2e:chromium disability-person-complete.spec.ts 运行 10 次

成功标准:

  • 10/10 次通过 = 100% 稳定性 ✅
  • 9/10 次通过 = 90% 稳定性,需要分析失败原因 ⚠️
  • < 9/10 次通过 = 稳定性不足,需要修复 ❌

Epic 2 状态: ✅ Done 回顾文档: _bmad-output/implementation-artifacts/epic-2-retrospective.md


Epic 3: 文件上传工具开发与验证

目标: 遵循 Epic 2 的成功模式,开发文件上传工具并在 web/tests/e2e/ 的真实测试中验证,解决当前测试超时阻塞问题。

背景:

  • Epic 1 和 Epic 2 已证明"先验证再扩展"策略的有效性
  • 当前残疾人管理测试在文件上传阶段超时(60秒),阻塞了完整验证
  • 优先开发文件上传工具,解决当前阻塞问题

范围:

  • ✅ 开发文件上传工具 uploadFileToField()
  • ✅ 编写单元测试(Vitest)
  • ✅ 在 web/tests/e2e/ 中验证工具
  • ✅ 收集反馈并修复问题
  • ✅ 稳定性验证(10次连续运行)

模式: 工具开发 → 真实 E2E 测试验证 → 问题修复 → 稳定性验证

依赖:

  • Epic 1: ✅ 已完成(类型定义、错误处理、基础设施)

验收标准:

  1. 文件上传工具在至少 3 处真实 E2E 测试中使用
  2. 所有测试连续运行 10 次,100% 通过率
  3. 测试超时问题已解决

Story 3.1: 开发文件上传工具函数

作为测试开发者, 我想要使用 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) And 配置对象继承 BaseOptions

函数签名:

export async function uploadFileToField(
  page: Page,
  selector: string,
  fileName: string,
  options?: FileUploadOptions
): Promise<void>

export interface FileUploadOptions extends BaseOptions {
  /** fixtures 目录路径,默认为 'tests/fixtures' */
  fixturesDir?: string;
  /** 是否等待上传完成,默认为 true */
  waitForUpload?: boolean;
}

参考架构决策:

  • 遵循 docs/standards/e2e-radix-testing.md 中的文件上传规范
  • 使用 DEFAULT_TIMEOUTS 常量定义超时
  • 错误处理使用 E2ETestErrorErrorContext

Story 3.2: 编写文件上传单元测试

作为测试开发者, 我想要文件上传工具有充分的单元测试, 以便确保函数的正确性和稳定性。

验收标准:

Given 文件上传工具函数已实现 When 创建 tests/unit/file-upload.test.ts Then 测试覆盖率 ≥ 80%(NFR29) And 测试用例包括:成功上传、文件不存在、选择器无效、超时 And 使用 Vitest 运行测试 And 所有测试通过

⚠️ Epic 2 关键经验应用:

  • 单元测试无法发现真实 DOM 问题,但可验证基本逻辑
  • 必须添加集成测试使用真实 Playwright API
  • 使用 Playwright Page mock 验证文件上传逻辑

Story 3.3: 在 web/tests/e2e 中验证文件上传工具

作为测试开发者, 我想要在 web/tests/e2e/ 的残疾人管理测试中使用文件上传工具, 以便验证工具在真实场景中的可用性。

验收标准:

Given 文件上传工具和单元测试已完成 Whenweb/tests/e2e/specs/admin/disability-person-complete.spec.ts 中使用工具 Then 至少迁移 3 处文件上传操作(身份证照片、残疾证照片) And 移除原有的自定义文件上传方法 And 测试在真实浏览器中通过 And 无测试超时问题

验证场景:

  • 身份证照片上传(正面、反面)
  • 残疾证照片上传
  • 个人照片上传(如果有)

参考 Epic 2.2-2.3 的迁移模式:

  • 渐进式迁移:先迁移部分测试
  • 保留原有方法作为 TODO 备份
  • 验证通过后再完全替换

Story 3.4: 收集反馈并修复问题

作为测试开发者, 我想要运行使用文件上传工具的测试并收集反馈, 以便发现潜在问题并改进工具。

验收标准:

Given 文件上传工具已在真实测试中使用 When 运行完整的 E2E 测试套件 Then 记录所有问题(失败的测试、错误消息、使用体验) Then 分类问题:工具 bug vs 使用错误 vs 改进建议 And 所有标记为"工具 bug"的问题已修复 And 测试连续运行 5 次通过 And 无 flaky 失败

优先级:

  • HIGH: 影响测试结果的问题(如上传失败、超时)
  • MEDIUM: 影响开发体验的问题(如错误消息不清晰)
  • LOW: 优化建议(如性能改进)

Story 3.5: 支持多文件同时上传

作为测试开发者, 我想要 uploadFileToField() 函数支持一次上传多个文件, 以便测试前端 <input type="file" multiple> 的多文件选择功能。

验收标准:

Given uploadFileToField() 函数已实现(单文件上传) When 扩展函数支持多文件上传 Then 函数接受文件名数组或字符串 And 使用 Playwright 的 setInputFiles([path1, path2, ...]) API And 支持相对路径数组(相对于 fixtures 目录) And 错误时提供清晰消息(包含所有文件路径) And 保持向后兼容(单文件上传仍然工作)

函数签名扩展:

// 支持单文件(向后兼容)
uploadFileToField(page, selector, fileName, options?): Promise<void>

// 支持多文件
uploadFileToField(page, selector, fileNames: string[], options?): Promise<void>

实现要点:

  • 使用函数重载或联合类型支持两种签名
  • 多文件时调用 setInputFiles(filePathArray)
  • 保持所有文件路径验证逻辑
  • 错误消息包含所有文件路径

测试用例:

  • 上传 3 张照片(身份证、残疾证正反面)
  • 混合格式(JPG、PNG、WEBP)
  • 一次性选择与分次上传的结果一致性验证

Story 3.6: 文件上传稳定性验证

作为测试开发者, 我想要验证文件上传工具的稳定性, 以便确保工具可以可靠地使用。

验收标准:

Given 所有问题已修复 When 连续运行文件上传相关测试 10 次 Then 所有测试 100% 通过 And 无超时失败 And 平均执行时间 ≤ 5 秒/文件

测试场景:

  • pnpm test:e2e:chromium disability-person-complete.spec.ts 运行 10 次
  • 重点验证文件上传相关步骤

成功标准:

  • 10/10 次通过 = 100% 稳定性 ✅
  • 9/10 次通过 = 90% 稳定性,需要分析失败原因 ⚠️
  • < 9/10 次通过 = 稳定性不足,需要修复 ❌

Epic 3 回顾:

  • 如果 100% 通过,可以进入 Epic 4
  • 如果 < 100%,需要分析并修复问题后再验证

Epic 4: 表单工具开发与验证

目标: 开发表单辅助工具并在 web/tests/e2e/ 的真实测试中验证。

说明: 遵循 Epic 2 和 Epic 3 的成功模式。

依赖: Epic 3 完成

模式: 工具开发 → 真实 E2E 测试验证 → 稳定性验证


Story 4.1: 开发表单辅助工具函数

作为测试开发者, 我想要使用 fillMultiStepForm()scrollToSection() 函数, 以便测试多步骤表单和滚动操作。

验收标准:

Given 类型定义已存在 When 实现 src/form-helper.ts 中的表单辅助函数 Then fillMultiStepForm(page, steps) 支持分步填写表单 And scrollToSection(page, sectionName) 滚动到特定区域 And 支持常见字段类型(文本、选择器、日期等) And 自动处理表单验证错误场景


Story 4.2: 编写表单工具单元测试

作为测试开发者, 我想要表单工具有充分的单元测试, 以便确保函数的正确性和稳定性。

验收标准:

Given 表单辅助工具函数已实现 When 创建 tests/unit/form-helper.test.ts Then 测试覆盖率 ≥ 80%(NFR29) And 测试用例包括:成功填写、滚动操作、验证错误等 And 使用 Vitest 运行测试 And 所有测试通过


Story 4.3: 在 web/tests/e2e 中验证表单工具

作为测试开发者, 我想要在残疾人管理测试中使用表单辅助工具, 以便验证工具在真实场景中的可用性。

验收标准:

Given 表单工具和单元测试已完成 When 在残疾人管理测试中使用工具 Then 验证多步骤表单填写 And 验证滚动操作 And 测试在真实浏览器中通过


Story 4.4: 表单稳定性验证

作为测试开发者, 我想要验证表单工具的稳定性, 以便确保工具可以可靠地使用。

验收标准:

Given 所有问题已修复 When 连续运行表单相关测试 10 次 Then 所有测试 100% 通过


Epic 5: 列表和对话框工具开发与验证

目标: 开发动态列表和对话框工具并在 web/tests/e2e/ 的真实测试中验证。

说明: 遵循 Epic 2-4 的成功模式。

依赖: Epic 4 完成

模式: 工具开发 → 真实 E2E 测试验证 → 稳定性验证


Story 5.1: 开发动态列表和对话框工具函数

作为测试开发者, 我想要使用 addDynamicListItem()deleteDynamicListItem() 和对话框工具, 以便测试银行卡管理、备注管理等动态列表功能。

验收标准:

Given 类型定义已存在 When 实现 src/dynamic-list.tssrc/dialog.ts 中的函数 Then addDynamicListItem(page, itemType, data) 添加新列表项 And deleteDynamicListItem(page, itemType, index) 删除指定索引的项 And handleDialog(page, action) 支持 confirm/cancel/close 操作 And waitForDialogClosed(page) 等待对话框完全关闭 And 支持不同类型列表项(银行卡、备注等)


Story 5.2: 编写列表和对话框单元测试

作为测试开发者, 我想要列表和对话框工具有充分的单元测试, 以便确保函数的正确性和稳定性。

验收标准:

Given 列表和对话框工具函数已实现 When 创建 tests/unit/dynamic-list.test.tsdialog.test.ts Then 测试覆盖率 ≥ 80%(NFR29) And 测试用例包括:添加、删除、打开/关闭对话框等 And 使用 Vitest 运行测试 And 所有测试通过


Story 5.3: 在 web/tests/e2e 中验证列表和对话框工具

作为测试开发者, 我想要在残疾人管理测试中使用列表和对话框工具, 以便验证工具在真实场景中的可用性。

验收标准:

Given 列表和对话框工具及单元测试已完成 When 在残疾人管理测试中使用工具 Then 验证银行卡管理(添加、删除) And 验证备注管理 And 测试在真实浏览器中通过


Story 5.4: 列表和对话框稳定性验证

作为测试开发者, 我想要验证列表和对话框工具的稳定性, 以便确保工具可以可靠地使用。

验收标准:

Given 所有问题已修复 When 连续运行列表和对话框相关测试 10 次 Then 所有测试 100% 通过


Epic 6: 完整验证(残疾人管理)

目标: 工具包在真实的残疾人管理 E2E 测试中完整验证,证明所有工具函数可用且稳定。

依赖: Epic 5 完成


Story 6.1: 完整流程测试

作为测试开发者, 我想要在残疾人管理完整流程测试中使用所有工具, 以便演示所有工具函数的综合使用。

验收标准:

Given Epic 1-5 的所有工具已实现并验证 When 确保 disability-person-complete.spec.ts 使用所有工具 Then 基本信息:使用 selectRadixOptionselectRadixOptionAsync And 照片上传:使用 uploadFileToField (来自 Epic 3) And 表单操作:使用 fillMultiStepForm, scrollToSection (来自 Epic 4) And 银行卡管理:使用 handleDialog, addDynamicListItem, deleteDynamicListItem (来自 Epic 5) And 备注添加:使用 addDynamicListItem (来自 Epic 5) And 所有测试通过


Story 6.2: 稳定性测试

作为测试开发者, 我想要有稳定性测试验证工具包的可靠性, 以便确保工具函数连续运行 20 次 100% 通过。

验收标准:

Given 完整流程测试已编写 When 创建稳定性测试或运行现有测试 20 次 Then 测试连续运行 20 次完整流程 And 验证 100% 通过率(NFR1) And 测试执行时间符合性能标准(NFR8-NFR11) And 无 flaky 失败 And 使用 Playwright 运行稳定性测试


Epic 7: 完善文档与开发者体验

目标: 测试开发者可以在 30 分钟内上手使用工具包,有完整的文档、示例和迁移指南。

依赖: Epic 6 完成


Story 7.1: 完善 README、API 文档和示例

作为测试开发者, 我想要有完整的 README 和 API 文档, 以便快速上手使用工具包。

验收标准:

Given Epic 1-6 的所有功能已实现 When 完善 README.md 和 API 文档 Then README 包含:项目简介、安装说明、快速入门、API 文档 And 每个工具函数都有完整的使用示例 And 说明静态 Select 和异步 Select 的区别和使用场景 And 包含迁移指南(从现有测试代码到工具函数) And 包含常见问题和解决方案 And 残疾人管理测试作为完整示例 And 所有函数有完整的 JSDoc 注释


Story 7.2: VS Code Snippets 和开发体验

作为测试开发者, 我想要有 VS Code 代码片段, 以便加速测试开发。

验收标准:

Given README 和 API 文档已完成 When 创建 VS Code snippets 配置 Then 提供常用代码片段(selectRadixOption, uploadFileToField 等) And 片段有清晰的触发词和描述 And 文档说明如何安装和使用 snippets And 开发者可以在 30 分钟内使用工具包编写第一个测试


Epic 8: 区域管理 E2E 测试 (Epic B)

目标: 测试开发者可以为区域管理功能编写完整的 E2E 测试,验证省/市/区/街道的添加、编辑、删除和级联选择功能。

业务分组: Epic B(业务测试 Epic)

背景:

  • Epic A(残疾人管理)已完成 Select 工具在真实 E2E 测试中的验证
  • 区域管理是下一个需要建立 E2E 测试覆盖的核心业务模块
  • 涉及四级级联选择(省/市/区/街道)和树形结构展示
  • 可能需要扩展现有工具或新增专用工具

范围:

  • ✅ 区域列表查看测试
  • ✅ 添加区域测试(省/市/区/街道)
  • ✅ 编辑区域测试
  • ✅ 删除区域测试
  • ✅ 级联选择测试(省市区街道四级联动)
  • ✅ 完整流程测试
  • ✅ 稳定性验证(10次连续运行)
  • ❌ 不修改后端业务逻辑
  • ❌ 不修改前端 UI 组件

模式: 业务测试为主,工具包支持为辅(遵循 Epic A 成功模式)

依赖:

  • Epic 1: ✅ 已完成(Select 工具基础框架)
  • Epic 2: ✅ 已完成(Select 工具在真实 E2E 测试中验证)

验收标准:

  1. 区域管理核心功能有完整的 E2E 测试覆盖
  2. 所有测试连续运行 10 次,100% 通过率
  3. 必要时扩展 e2e-test-utils 工具包(级联选择、树形结构等)
  4. 测试可作为其他业务模块 E2E 测试的参考

交付物:

  • 区域列表 Page Object
  • 添加区域测试用例
  • 编辑区域测试用例
  • 删除区域测试用例
  • 级联选择测试用例
  • 稳定性验证报告
  • 工具包扩展文档(如有)

FRs covered: FR1-FR50(复用现有工具,必要时扩展)


Story 8.1: 创建区域管理 Page Object

作为测试开发者, 我想要创建区域管理的 Page Object, 以便组织区域管理相关的页面元素和操作。

验收标准:

Given Epic 2 的 Page Object 模式已验证 When 创建 web/tests/e2e/pages/admin/region-management.page.ts Then 定义区域列表页面的选择器和操作方法 And 定义添加区域对话框的选择器和操作方法 And 定义编辑区域对话框的选择器和操作方法 And 遵循现有 Page Object 设计模式 And 所有方法有完整的 TypeScript 类型定义

参考:

  • web/tests/e2e/pages/admin/disability-person.page.ts 作为参考
  • 遵循项目的 Page Object 设计模式

Story 8.2: 编写区域列表查看测试

作为测试开发者, 我想要编写区域列表查看的 E2E 测试, 以便验证区域列表的基本功能和数据展示。

验收标准:

Given 区域管理 Page Object 已创建 When 编写区域列表查看测试用例 Then 验证区域列表按预期加载 And 验证区域数据的正确展示(名称、层级、状态等) And 验证分页功能(如适用) And 验证搜索功能(如适用) And 测试在真实浏览器中通过


Story 8.3: 编写添加区域测试

作为测试开发者, 我想要编写添加区域的 E2E 测试, 以便验证省/市/区/街道的添加功能。

验收标准:

Given 区域列表查看测试已通过 When 编写添加区域测试用例 Then 验证添加省级区域的流程 And 验证添加市级区域的流程(需选择父级省份) And 验证添加区级区域的流程(需选择父级城市) And 验证添加街道级区域的流程(需选择父级区域) And 使用 selectRadixOptionselectRadixOptionAsync 选择父级区域 And 验证添加成功后列表中显示新区域 And 测试在真实浏览器中通过

级联选择测试点:

  • 选择省份后,市级下拉框的选项是否正确过滤
  • 选择城市后,区级下拉框的选项是否正确过滤
  • 选择区域后,街道下拉框的选项是否正确过滤

Story 8.4: 编写编辑区域测试

作为测试开发者, 我想要编写编辑区域的 E2E 测试, 以便验证区域信息的修改功能。

验收标准:

Given 添加区域测试已通过 When 编写编辑区域测试用例 Then 验证编辑区域名称的流程 And 验证修改区域状态的流程(如启用/禁用) And 验证编辑后列表中正确显示更新后的信息 And 验证必填字段的验证规则 And 测试在真实浏览器中通过


Story 8.5: 编写删除区域测试

作为测试开发者, 我想要编写删除区域的 E2E 测试, 以便验证区域的删除功能和相关约束。

验收标准:

Given 编辑区域测试已通过 When 编写删除区域测试用例 Then 验证删除无子级区域的流程 And 验证删除有子级区域时的错误提示 And 验证删除确认对话框的正确操作 And 验证删除成功后列表中不再显示该区域 And 测试在真实浏览器中通过


Story 8.6: 编写级联选择完整流程测试

作为测试开发者, 我想要编写完整的四级级联选择测试, 以便验证省/市/区/街道联动的完整场景。

验收标准:

Given 单独的区域操作测试已通过 When 编写完整的级联选择流程测试 Then 从选择省份开始,依次选择市、区、街道 And 验证每级选择后,下一级选项正确加载 And 验证上级变更时,下级选择被清空 And 验证完整的添加流程(省份→城市→区域→街道) And 测试在真实浏览器中通过

工具需求评估:

  • 评估现有 selectRadixOptionAsync 是否满足需求
  • 如不满足,记录到 Story 8.8 进行工具扩展

Story 8.7: 运行测试并收集问题和改进建议

作为测试开发者, 我想要运行区域管理测试并收集反馈, 以便发现潜在问题并改进测试或工具。

验收标准:

Given 所有区域管理测试用例已编写 When 运行完整的区域管理 E2E 测试套件 Then 记录所有问题(失败的测试、错误消息、使用体验) Then 分类问题:业务逻辑 bug vs 测试代码问题 vs 工具不足 And 整理成问题清单 And 识别是否需要扩展 e2e-test-utils 工具包

关注点:

  • 现有 Select 工具是否满足级联选择需求?
  • 是否需要级联选择专用工具?
  • 是否需要树形结构操作工具?
  • 错误消息是否清晰?

Story 8.8: 扩展工具包(如需要)

作为测试开发者, 我想要根据 Story 8.7 的发现扩展 e2e-test-utils 工具包, 以便更好地支持区域管理等业务模块的测试。

验收标准:

Given Story 8.7 已识别工具扩展需求 When 实现必要的工具扩展 Then 如需级联选择工具:实现 selectCascadeOptions() 函数 And 如需树形结构工具:实现 selectTreeNode() 函数 And 编写工具函数的单元测试 And 在区域管理测试中验证新工具 And 更新工具包文档

可能的工具扩展:

// 级联选择工具(示例)
export async function selectCascadeOptions(
  page: Page,
  levels: Array<{label: string, value: string}>
): Promise<void>

// 树形结构选择工具(示例)
export async function selectTreeNode(
  page: Page,
  treeLabel: string,
  nodePath: string[]
): Promise<void>

依赖:

  • 仅在 Story 8.7 确认需要时才执行此 Story
  • 如无需扩展,此 Story 可标记为 N/A

Story 8.9: 区域管理稳定性验证

作为测试开发者, 我想要验证区域管理测试的稳定性, 以便确保测试可以可靠地使用。

验收标准:

Given 所有问题已修复(包括工具扩展) When 连续运行区域管理相关测试 10 次 Then 所有测试 100% 通过 And 无 flaky 失败 And 平均执行时间符合预期

测试场景:

  • pnpm test:e2e:chromium region-management.spec.ts 运行 10 次

成功标准:

  • 10/10 次通过 = 100% 稳定性 ✅
  • 9/10 次通过 = 90% 稳定性,需要分析失败原因 ⚠️
  • < 9/10 次通过 = 稳定性不足,需要修复 ❌

Epic 8 回顾:

  • 如果 100% 通过,Epic B 完成,可进入下一个业务模块
  • 如果 < 100%,需要分析并修复问题后再验证