epic-2-retrospective.md 14 KB

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

会议日期: 2026-01-10 Epic 状态: ✅ Done 参与人员: Root (Project Lead), Bob (Scrum Master), Alice (Product Owner), Charlie (Senior Dev), Dana (QA Engineer), Elena (Junior Dev)

会议概览

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

交付成果:

  • 完成故事: 5/5 (100%) - Story 2.6 稳定性验证已跳过
  • Select 工具验证: ✅ 通过(静态 + 异步场景)
  • 关键 Bug 修复: ✅ listbox → option DOM 结构问题

会议目的:

  1. 学习 Epic 2 的执行经验
  2. 评估 Epic 1 回顾行动项的跟进情况
  3. 为 Epic 3(扩展工具集)做准备

成功经验 ✅

1. "先验证再扩展" 策略得到验证

Epic 1 回顾中的关键决策在 Epic 2 中得到了验证:

原 Epic 规划顺序:

  • Epic 1: Select 工具(已完成)
  • Epic 2: 扩展工具集
  • Epic 3: 验证

修正后的顺序:

  • Epic 1: Select 工具(已完成)
  • Epic 2: 验证 Select 工具 ← 当前 Epic
  • Epic 3: 扩展工具集
  • Epic 4: 全面验证

Alice (Product Owner): "这个决策非常正确。如果我们先扩展更多工具,Select 工具的问题会在 Epic 3/4 中才暴露,那时修复成本会高得多。"

验证结果:

Story 验证内容 结果 发现问题
2.1 工具包安装和类型安全 ✅ 通过
2.2 静态 Select 迁移(5 处) ✅ 通过
2.3 异步 Select 迁移(省份/城市) ✅ 通过 移除了 waitForTimeout hack
2.4 运行测试并收集问题 ⚠️ 发现 DOM 结构假设错误
2.5 验证修复效果 ✅ 通过

2. 发现并修复关键 DOM 结构 Bug

问题详情 (Story 2.4):

// ❌ 原代码 - 等待 listbox 元素
await page.waitForSelector('[role="listbox"]', {
  timeout: DEFAULT_TIMEOUTS.static,
  state: 'visible'
});

// ✅ 修复 - 直接等待 option 元素
// findTrigger 和 findAndClickOption 中使用 getByRole("option")

Charlie (Senior Dev): "这个 bug 很关键。Epic 1 的单元测试没有发现这个问题,因为单元测试模拟了完整的 DOM 结构。真实环境中的 Radix UI Select v2.2.5 结构与假设不同。"

修复内容:

  1. selectRadixOption: 改用 getByRole("option") 代替 waitForSelector("[role=listbox]")
  2. selectRadixOptionAsync: 应用相同修复
  3. 添加下拉框关闭等待逻辑(200ms + hidden 状态)
  4. 缩短选择器超时(5000ms → 2000ms)

验证结果 (Story 2.5):

✅ 姓名: 完整测试_1768004957534
✅ 性别: 男
✅ 身份证号: 420101199001011234
✅ 残疾证号: 51100119900104
✅ 残疾类型: 视力残疾
✅ 残疾等级: 一级
✅ 联系电话: 13800138004
✅ 身份证地址: 湖北省武汉市测试街道1号
✅ 省份: 湖北省
✅ 城市: 武汉市

3. 代码审查流程持续有效

Epic 2 每个故事都经过了代码审查,问题全部修复:

Story 审查问题数 状态
2.1 3 个(文档相关) ✅ 全部修复
2.2 多个(行号更新、实现调整) ✅ 全部修复
2.3 9 个(MEDIUM、LOW) ✅ 全部修复
2.4 初始发现问题 ✅ 已修复
2.5 1 个(.bak 文件) ✅ 已修复

Dana (QA Engineer): "代码审查继续发挥价值。Story 2.5 中发现的 .bak 文件问题虽然小,但这种细节关注保持了代码库的整洁。"

4. 真实 E2E 测试的价值

单元测试 vs E2E 测试:

测试类型 覆盖场景 发现的问题
单元测试 (Epic 1) 模拟 DOM 结构
E2E 测试 (Epic 2) 真实 Radix UI 组件 listbox DOM 问题

Elena (Junior Dev): "Epic 1 的单元测试覆盖率达到了 93.65%,但仍然没有发现这个 DOM 结构问题。真实 E2E 测试是不可替代的。"


[第一部分完 - 会议概览和成功经验]

挑战和问题分析 ⚠️

1. DOM 结构假设与实际不符

问题描述:

工具假设 Select 组件的 DOM 结构包含 [role="listbox"] 元素,但 Radix UI Select v2.2.5 的实际结构是:

[role="combobox"]
  └── [role="option"]  ← 选项直接在 combobox 内部

影响:

  • 导致 waitForSelector('[role="listbox"]') 超时
  • 测试在第一个 Select 操作时失败
  • 阻塞了整个 Epic 2 的验证

根本原因分析:

Bob (Scrum Master): "为什么单元测试没有发现这个问题?"

Charlie (Senior Dev): "因为单元测试中的 mock DOM 结构是我们假设的完美结构。我们没有使用真实的 Radix UI 组件进行测试。"

教训:

  • 单元测试不能完全替代集成/E2E 测试
  • 需要在真实组件上验证工具
  • DOM 结构假设应该基于实际实现而非理想模型

2. Epic 1 回顾行动项未完全跟进

Epic 1 HIGH 优先级行动项跟进情况:

行动项 状态 影响
HIGH #1: 配置 ESLint 规则 ❌ 未完成 Epic 2 中仍有重复的代码风格问题
HIGH #2: 更新架构文档记录 TS+Playwright 陷阱 ⏳ 部分完成 开发者需要自己摸索
HIGH #3: 创建新的 Epic 2 ✅ 完成 Epic 2 成功执行
HIGH #4: 更新 Epic 编号 ✅ 完成 sprint-status 已更新

Alice (Product Owner): "HIGH #1#2 没有完成。这可能是为什么我们在 Epic 2 中仍遇到一些预期内的问题。"

未完成的行动项影响:

  1. ESLint 规则未配置

    • Epic 2 中仍然出现代码风格问题
    • 例如:Story 2.5 中的 .bak 文件未清理
    • 代码审查时间被浪费在可自动检测的问题上
  2. 架构文档未更新

    • TypeScript + Playwright 陷阱没有正式记录
    • 新开发者需要自己摸索
    • 知识传递效率低

3. 渐进式迁移策略的额外成本

Story 2.2 → Story 2.3 的迁移策略:

Story 范围 状态
2.2 静态 Select ✅ 完成,但保留自定义方法
2.3 异步 Select ✅ 完成,移除自定义方法

额外成本:

  • Story 2.2 需要添加 TODO 注释
  • Story 2.3 需要再次修改相同文件
  • 需要协调两个故事的边界

Charlie (Senior Dev): "渐进式迁移策略保持了测试连续性,但确实增加了协调成本。如果一次性迁移所有 Select,风险会更高。这是一个权衡。"

4. 测试超时问题(非工具问题)

问题描述:

  • 测试在文件上传阶段超时(60秒)
  • 与 Select 工具无关,是测试流程问题

当前状态:

  • 标记为 LOW 优先级
  • 需要在后续 Epic 中处理(Epic 4: 文件上传测试)

Dana (QA Engineer): "测试超时不是 Select 工具的问题,但它影响了 Epic 2 的完整验证。我们无法运行完整的测试套件来验证所有字段。"


[第二部分完 - 挑战和问题分析]

Epic 1 回顾行动项跟进 📋

HIGH 优先级行动项

# 行动项 负责人 预计时间 Epic 2 状态
1 配置 ESLint 规则捕获常见问题 Charlie 2h 未完成
2 更新架构文档记录 TS+Playwright 陷阱 Charlie 1h 部分完成
3 创建新的 Epic 2 Bob 1h 已完成
4 更新 Epic 编号(2→3, 3→4, 4→5) Bob 0.5h 已完成

详细分析

行动项 #1: ESLint 规则 - 未完成

原计划 (Epic 1 回顾):

// .eslintrc.js
{
  rules: {
    'no-constant-binary-expression': 'error',
    'no-unused-vars': 'error',
    'no-empty': ['error', { allowEmptyCatch: false }],
    'prefer-const': 'error'
  }
}

Epic 2 中的影响:

  • Story 2.5 发现了未清理的 .bak 文件
  • 代码审查仍然需要人工检查可自动检测的问题

建议: 在 Epic 3 开始前完成此行动项

行动项 #2: 架构文档更新 - 部分完成

Epic 2 中的证据:

  • Story 2.2 Dev Notes 引用了 Epic 1 回顾中的 TypeScript + Playwright 陷阱
  • 但架构文档本身未更新

Charlie (Senior Dev): "我在故事中引用了这些经验,但没有正式更新到架构文档中。这是我的疏忽。"

行动项 #3-4: Epic 规划调整 - 已完成 ✅

Epic 2 成功创建并执行:

  • 使用现有 web/tests/e2e/ 测试基础设施
  • 验证了 Select 工具在真实场景中的可用性
  • 发现并修复了关键 DOM 结构问题

Alice (Product Owner): "Epic 规划调整非常成功。'先验证再扩展'的策略得到了验证。"

MEDIUM 优先级行动项

# 行动项 负责人 Epic 2 状态
5 创建开发者自查清单 Elena ❌ 未完成
6 更新代码审查检查清单 Charlie ⏳ 部分完成

行动项 📋

优先级 HIGH

1. 配置 ESLint 规则(从 Epic 1 延续)

负责人: Charlie 预计时间: 2 小时 截止日期: Epic 3 开始前

需要配置的规则:

// .eslintrc.js
{
  rules: {
    // 捕获冗余的 null 检查
    'no-constant-binary-expression': 'error',

    // 捕获未使用的变量
    'no-unused-vars': 'error',

    // 捕获空 catch 块
    'no-empty': ['error', { allowEmptyCatch: false }],

    // 首选 const
    'prefer-const': 'error'
  }
}

预期收益: 自动捕获约 50% 的重复审查问题

2. 更新架构文档记录 TS+Playwright 陷阱(从 Epic 1 延续)

负责人: Charlie 预计时间: 1 小时 截止日期: Epic 3 开始前

文档位置: _bmad-output/planning-artifacts/architecture.md

需要添加的内容:

  • TypeScript DOM 类型问题及解决方案
  • 精确文本匹配选择器规范
  • DOM 结构假设必须基于真实组件验证

3. 更新工具包单元测试策略

负责人: Dana (QA Engineer) 预计时间: 2 小时 截止日期: Epic 3 开始前

问题: 当前单元测试使用模拟 DOM,无法发现真实 DOM 结构问题

建议解决方案:

  • 在单元测试中使用真实的 Radix UI 组件
  • 或添加集成测试级别,使用真实组件

Elena (Junior Dev): "如果我们使用真实组件进行单元测试,Epic 2 的 DOM 问题就能在 Epic 1 中发现。"

优先级 MEDIUM

4. 创建开发者自查清单(从 Epic 1 延续)

负责人: Elena 预计时间: 1 小时

清单内容:

  • 所有导出函数都有完整的 JSDoc
  • 内部函数使用 @internal 标记
  • 错误处理使用 E2ETestError 而非原生 Error
  • DOM 结构假设必须基于真实组件验证
  • 文本选择器使用 :text-is() 而非 :has-text()
  • 配置对象继承 BaseOptions
  • 超时值使用 DEFAULT_TIMEOUTS 常量

5. 解决测试超时问题

负责人: Dana (QA Engineer) 预计时间: 1-2 小时

问题描述:

  • 测试在文件上传阶段超时(60秒)
  • 影响完整测试套件的执行

可能的解决方案:

  1. 增加测试超时时间
  2. 优化文件上传逻辑
  3. 分离文件上传测试到独立套件

当前计划: 在 Epic 4(文件上传测试)中处理

优先级 LOW

6. 更新代码审查检查清单(从 Epic 1 延续)

负责人: Charlie 预计时间: 0.5 小时

添加检查点:

  • 检查 DOM 结构假设是否基于真实组件验证
  • 验证是否遵循"先验证再扩展"原则

关键决策 🎯

决策 1: 跳过 Story 2.6 稳定性验证

原计划:

  • Story 2.6: 稳定性验证(连续 10 次,100% 通过)

实际情况:

  • Story 2.5 已确认 Select 工具工作正常
  • 所有字段都成功填写
  • 测试超时与 Select 工具无关

决策: 跳过 Story 2.6,Epic 2 标记为完成

理由:

  1. Select 工具已充分验证(静态 + 异步场景)
  2. 10 次稳定性测试的边际收益递减
  3. 测试超时问题阻塞了完整验证
  4. Epic 3(扩展工具集)更有价值

Alice (Product Owner): "我同意跳过 Story 2.6。Select 工具已经验证充分,继续扩展工具集的价值更高。"

决策 2: 单元测试策略调整

问题: 单元测试使用模拟 DOM,无法发现真实 DOM 结构问题

可选方案:

方案 优点 缺点
A. 继续使用模拟 DOM 快速、独立 无法发现 DOM 问题
B. 使用真实组件 发现真实问题 依赖外部组件
C. 添加集成测试 两全其美 增加测试层级

决策: 采用方案 C - 添加集成测试级别

Charlie (Senior Dev): "单元测试应该保持快速和独立。我们添加一个集成测试级别,使用真实组件验证工具。"

决策 3: Epic 3 前完成 HIGH 优先级行动项

未完成的 HIGH 行动项:

  1. 配置 ESLint 规则
  2. 更新架构文档
  3. 调整单元测试策略

决策: Epic 3 暂缓,先完成这些行动项

理由:

  1. 这些改进将降低 Epic 3 的代码审查成本
  2. 文档更新将提高 Epic 3 的开发效率
  3. 测试策略调整将避免类似 DOM 问题再次发生

Bob (Scrum Master): "我们花 2-3 小时完成这些改进,Epic 3 会更顺利。这是值得的前期投入。"


总结 📝

Epic 2 状态:Done

关键成果:

  • ✅ Select 工具在真实 E2E 测试中验证通过
  • ✅ 发现并修复关键 DOM 结构问题
  • ✅ "先验证再扩展"策略得到验证
  • ✅ 代码审查流程持续有效

关键经验:

  1. 真实 E2E 测试不可替代 - 单元测试无法发现 DOM 结构问题
  2. DOM 结构假设必须验证 - 不能基于理想模型开发工具
  3. 渐进式迁移有价值 - 但需要额外的协调成本
  4. 行动项跟进很重要 - Epic 1 的未完成行动项影响了 Epic 2

下一步:

  1. ✅ Epic 2 完成并归档
  2. 🆕 完成技术改进(ESLint、文档、测试策略)
  3. ⏸️ Epic 3 暂缓,等待改进完成
  4. 📋 创建 Epic 3 准备检查清单

Bob (Scrum Master): "Epic 2 是一个成功的验证 Epic。我们发现并修复了关键问题,验证了架构决策的正确性。更重要的是,我们学到了真实 E2E 测试的价值,这将指导后续的开发。"


[文档完]