epic-1-retrospective.md 13 KB

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

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

会议概览

Epic 1 目标: 测试开发者可以安装 @d8d/e2e-test-utils 包,立即使用 Select 工具测试 Radix UI Select 组件。

交付成果:

  • 完成故事: 6/6 (100%)
  • 单元测试: 37/37 通过 (100%)
  • 测试覆盖率: 93.65% Statements, 88.09% Branches
  • 类型检查: ✅ 通过

会议目的:

  1. 学习 Epic 1 的执行经验
  2. 为下一个 Epic 的成功做准备

成功经验 ✅

1. 代码审查流程有效

代码审查在 Epic 1 中发挥了关键作用:

故事 审查问题 HIGH MEDIUM LOW 状态
1.1 9 3 3 2 全部修复
1.2 4 1 2 1 全部修复
1.3 8 2 6 0 全部修复
1.4 7 2 5 0 全部修复
1.5 6 0 4 2 全部修复
1.6 5 0 4 1 全部修复
总计 39 8 24 7 100% 修复

关键发现:

  • HIGH 级问题从 Story 1.1-1.4 的 8 个降至 Story 1.5-1.6 的 0 个
  • 所有问题无一遗漏,全部得到修复
  • 团队从审查中学习并应用到下一个故事

Charlie (Senior Dev): "Story 1.3 的审查发现的问题尤其关键。如果我们没有发现 :has-text() 会部分匹配的问题,测试可能会在错误选项上通过,导致严重的假阳性 bug。"

2. 持续改进模式

从前一个故事的经验传递到下一个故事:

经验来源 应用故事 内容
Story 1.3 审查 Story 1.4 DOM 类型问题处理、精确文本匹配
Story 1.4 实现 Story 1.6 单元测试 Mock 策略、重试机制测试
Story 1.6 测试 Bug 修复 发现并修复网络空闲等待超时配置 bug

Elena (Junior Dev): "Charlie 在 Story 1.3 的审查后让我把每个内部函数都加上完整的 JSDoc。虽然一开始觉得麻烦,但后来写 Story 1.4 的测试时发现这些文档真的很有帮助。"

3. 测试质量提升

测试覆盖率从 Story 1.1 的基础占位测试提升到 Story 1.6 的优秀覆盖率:

  • Statements: 93.65% (目标: ≥80%)
  • Branches: 88.09% (目标: ≥80%)
  • Functions: 100% (目标: ≥80%)
  • Lines: 93.65% (目标: ≥80%)

Dana (QA Engineer): "Story 1.6 更有意思——我们在写单元测试的过程中发现了一个实际的 bug:selectRadixOptionAsync 的网络空闲等待超时配置不对。这证明代码审查和测试是互补的。"

4. 类型系统基础扎实

Epic 1 建立的类型系统为后续开发奠定了基础:

  • BaseOptions - 所有配置对象的基类
  • ErrorContext - 结构化错误信息
  • E2ETestError - 统一的错误处理
  • AsyncSelectOptions, FileUploadOptions, FormStepOptions, DialogOptions - 特定选项类型

Charlie (Senior Dev): "我们在 Epic 1 建立的类型系统是一个很大的胜利。BaseOptions 作为所有配置对象的基类、E2ETestError 提供结构化错误信息,这些设计模式在后续故事中持续复用,减少了重复代码。"


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

挑战和问题分析 ⚠️

1. 重复出现的审查问题

代码审查发现的 39 个问题中,有相当一部分是重复出现的:

问题类型 出现次数 可预防? 预防方法
冗余 null 检查 5+ ✅ 是 ESLint 规则
缺少 JSDoc 8+ ✅ 是 ESLint 规则
空 catch 块 4+ ✅ 是 ESLint 规则
DOM 类型问题 1 ✅ 是 架构文档
文本选择器精确性 1 ✅ 是 编码规范

Dana (QA Engineer): "这 18+ 个重复问题占总数的近一半。如果能通过工具或文档预防,就能节省约 8 小时的修复时间。"

成本分析:

  • 每个问题平均修复时间:25 分钟
  • 18 个可预防问题 × 25 分钟 = 7.5 小时
  • 预防优于治疗: 配置 ESLint 规则只需 2 小时,一次性解决问题

2. TypeScript + Playwright DOM 类型问题

Elena (Junior Dev): "Story 1.3 的 DOM 类型问题真的让我很困惑。page.evaluate() 在 TypeScript 中总是报错,我花了很长时间才找到 page.locator().allTextContents() 这个解决方案。"

问题详情:

  • 使用 page.evaluate() 获取文本内容会触发 TypeScript DOM 类型错误
  • Playwright 的类型定义与浏览器 DOM 环境不完全兼容

解决方案:

// ❌ 不推荐 - TypeScript 类型问题
const text = await page.evaluate(el => el.textContent, element);

// ✅ 推荐 - 使用 Playwright API
const text = await element.textContent();
// 或
const texts = await page.locator(selector).allTextContents();

Charlie (Senior Dev): "我应该在架构文档中注明这一点,而不是让你自己去摸索。"

3. 精确文本匹配问题

问题: 使用 :has-text() 选择器会进行部分匹配,可能导致误选错误选项。

Story 1.3 发现的案例:

  • 期望选择 "广东省"
  • 实际选择了 "广东省xx市"(因为包含 "广东省")

解决方案:

// ❌ 部分匹配 - 可能误选
page.locator(`.option:has-text("广东省")`)

// ✅ 精确匹配 - 只匹配完全相等的文本
page.locator(`.option:text-is("广东省")`)

影响: 如果没有在代码审查中发现,测试可能会在错误选项上通过,导致假阳性 bug。

4. 网络空闲等待超时配置 Bug

Story 1.6 单元测试中发现:

// ❌ Bug - 网络空闲等待使用了默认的 networkIdle 超时
await page.waitForLoadState('networkidle', { timeout: DEFAULT_TIMEOUTS.networkIdle });

// ✅ 修复 - 使用用户自定义的 timeout
await page.waitForLoadState('networkidle', { timeout: options.timeout ?? DEFAULT_TIMEOUTS.async });

Dana (QA Engineer): "这证明代码审查和测试是互补的。审查可以发现问题,但单元测试能在实际执行中暴露隐藏的 bug。"

5. Epic 规划问题(Root 发现)

问题 1: Epic 顺序错误

原规划顺序:

  • Epic 1: ✅ Select 工具(已完成)
  • Epic 2: 扩展工具集(文件上传、表单等)
  • Epic 3: 在残疾人管理中验证工具包
  • Epic 4: 完善文档

Root (Project Lead): "为什么先扩展更多工具,而不是先验证现有工具?如果我们现在构建的工具不能用,Epic 2 会浪费大量时间。"

正确顺序:

  • Epic 1: ✅ Select 工具(已完成)
  • Epic 2 (新): 在现有 E2E 测试中验证 Select 工具
  • Epic 3 (原 Epic 2): 扩展工具集
  • Epic 4 (原 Epic 3): 全面验证
  • Epic 5 (原 Epic 4): 完善文档

问题 2: 重复建设而非复用

原 Epic 3 Story 3.1 计划创建 tests/test-app/ 独立测试应用,而不是使用现有的 web/tests/e2e/

Root (Project Lead): "现有的 web 目录已经有 E2E 测试了。为什么要另外创建一个 test-app?直接在现有测试中使用工具包更高效。"

Alice (Product Owner): "这个修正更符合敏捷原则——利用现有资源,而不是重复建设。"

Charlie (Senior Dev): "而且从测试角度看,在真实的残疾人管理测试中使用 Select 工具更能发现实际问题。"


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

行动项 📋

优先级 HIGH

1. 配置 ESLint 规则捕获常见问题

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

需要配置的规则:

// .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. 更新架构文档记录 TypeScript + Playwright 陷阱

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

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

需要添加的内容:

  • TypeScript DOM 类型问题及解决方案
  • 精确文本匹配选择器规范
  • 常见陷阱和最佳实践

3. 创建新的 Epic 2

负责人: Bob (Scrum Master) 预计时间: 1 小时

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

包含的故事: | 故事 | 内容 | 预计时间 | |------|------|----------| | 2.1 | 在 web 目录安装 @d8d/e2e-test-utils | 0.5h | | 2.2 | 使用 selectRadixOption 重写残疾类型选择测试 | 1h | | 2.3 | 使用 selectRadixOptionAsync 重写省份/城市选择测试 | 1.5h | | 2.4 | 运行测试并收集问题和改进建议 | 1h | | 2.5 | 修复发现的问题(如有) | 取决于发现 | | 2.6 | 稳定性验证(连续 10 次,100% 通过) | 0.5h |

预计总工作量: 4-6 小时 + 修复时间

4. 更新 Epic 编号

负责人: Bob (Scrum Master) 预计时间: 0.5 小时

变更:

  • 原 Epic 2 → Epic 3
  • 原 Epic 3 → Epic 4
  • 原 Epic 4 → Epic 5

优先级 MEDIUM

5. 创建开发者自查清单

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

清单内容:

  • 所有导出函数都有完整的 JSDoc
  • 内部函数使用 @internal 标记
  • 错误处理使用 E2ETestError 而非原生 Error
  • 文本选择器使用 :text-is() 而非 :has-text()
  • 配置对象继承 BaseOptions
  • 超时值使用 DEFAULT_TIMEOUTS 常量

6. 更新代码审查检查清单

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

添加检查点:

  • 检查是否复用现有基础设施而非创建新应用
  • 验证是否遵循"先验证再扩展"原则

7. 更新 Epic 规划模板

负责人: Bob (Scrum Master) 预计时间: 0.5 小时

添加指导原则:

  • 鼓励先验证 MVP 再扩展功能
  • 优先复用现有资源而非重复建设
  • 每个功能完成后应有验证环节

优先级 LOW

8. 在 Epic 2 开始前完成技术改进

前置条件: 行动项 1-3 必须在启动新 Epic 2 之前完成


Epic 规划修正 🔄

修正后的 Epic 顺序

Epic 内容 状态
Epic 1 Select 工具基础框架 ✅ Done
Epic 2 (新) 在现有 E2E 测试中验证 Select 工具 🆕 To Be Created
Epic 3 扩展工具集(文件上传、表单、列表、对话框) ⏸️ Pending
Epic 4 全面验证工具包 ⏸️ Pending
Epic 5 完善文档与开发者体验 ⏸️ Pending

新 Epic 2 详细规划

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

目标:

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

范围:

  • ✅ 使用现有 web/tests/e2e/ 测试基础设施
  • ✅ 使用现有的残疾人管理测试场景
  • ❌ 不创建新的 test-app
  • ❌ 不添加新功能(仅验证现有功能)

验收标准:

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

关键决策 🎯

决策 1: 重新排列 Epic 顺序

原顺序: 构建 → 扩展 → 验证 新顺序: 构建 → **验证 → 扩展 → 全面验证

理由:

  1. 更快反馈 - 不用等所有工具做完再验证
  2. 降低风险 - 如果 Select 工具有问题,只修这一个工具
  3. 更好决策 - 验证后的经验可以指导后续工具设计
  4. 更小批次 - 每个 Epic 都是可独立交付的价值

决策 2: 使用现有基础设施

原计划: 创建 tests/test-app/ 独立测试应用 新计划: 使用现有 web/tests/e2e/ 测试

理由:

  1. 更快启动 - 无需搭建新应用
  2. 更真实 - 在实际业务场景中测试
  3. 更易维护 - 只有一个测试套件
  4. 更早发现 - 直接在现有测试中发现问题

决策 3: 技术改进先行

计划: 在启动新 Epic 2 之前完成技术改进(ESLint 配置、文档更新)

理由:

  1. 预防胜于治疗 - 节费 2 小时配置,节省 7.5 小时修复
  2. 一次性投资,持续受益 - 改进将惠及所有后续 Epic
  3. 建立标准 - 为团队建立清晰的编码规范

总结 📝

Epic 1 状态:Done

关键成果:

  • ✅ Select 工具函数完整实现
  • ✅ 93.65% 测试覆盖率
  • ✅ 37/37 单元测试通过
  • ✅ 类型检查通过
  • ✅ 所有代码审查问题已修复

关键经验:

  1. 代码审查流程有效,但应与预防措施结合
  2. 从前一个故事学习并应用到下一个故事效果显著
  3. 在真实场景中验证比构建更多功能更优先
  4. 利用现有基础设施比重复建设更高效

下一步:

  1. ✅ Epic 1 完成并归档
  2. 🆕 创建新 Epic 2(验证现有工具)
  3. 🔧 完成技术改进(ESLint、文档)
  4. ⏸️ 原 Epic 2-4 暂停,等待验证结果

Bob (Scrum Master): "这是一次非常成功的回顾会议。Root 的洞察帮助我们发现了 Epic 规划中的关键问题,避免在错误的方向上投入更多时间。感谢所有人的坦诚分享。"


[文档完]