# Story 10.7: 编写订单状态流转测试 Status: done ## Story 作为测试开发者, 我想要编写订单状态流转的 E2E 测试, 以便验证激活和关闭订单的功能。 ## Acceptance Criteria **Given** 订单 CRUD 测试已通过 **When** 编写订单状态流转测试用例 **Then** 包含以下测试场景: 1. **激活草稿订单** - 创建草稿状态订单 - 点击激活订单按钮 - 验证确认对话框显示 - 确认激活 - 验证订单状态变为进行中 2. **关闭进行中订单** - 激活订单后 - 点击关闭订单按钮 - 验证确认对话框显示 - 确认关闭 - 验证订单状态变为已完成 3. **状态限制验证** - 尝试激活非草稿状态的订单 - 验证按钮禁用或操作被阻止 - 尝试关闭非进行中状态的订单 - 验证操作限制正确 **测试文件:** `web/tests/e2e/specs/admin/order-status.spec.ts` ## Tasks / Subtasks - [x] 补充 Page Object 状态流转方法 (AC: When) - [x] 在 `OrderManagementPage` 中添加 `activateOrder()` 方法 - [x] 在 `OrderManagementPage` 中添加 `closeOrder()` 方法 - [x] 在 `OrderManagementPage` 中添加 `getOrderStatus()` 方法 - [x] 添加验证状态按钮状态的方法 - [x] 创建状态流转测试文件 (AC: When) - [x] 创建 `web/tests/e2e/specs/admin/order-status.spec.ts` - [x] 导入必要的测试依赖和 Page Object - [x] 编写激活草稿订单测试 (AC: Then #1) - [x] 测试创建草稿订单 - [x] 测试打开激活确认对话框 - [x] 测试确认激活操作 - [x] 验证订单状态从草稿变为进行中 - [x] 验证 Toast 成功消息显示 - [x] 编写关闭进行中订单测试 (AC: Then #2) - [x] 测试创建并激活订单(准备进行中状态) - [x] 测试打开关闭确认对话框 - [x] 测试确认关闭操作 - [x] 验证订单状态从进行中变为已完成 - [x] 验证 Toast 成功消息显示 - [x] 编写状态限制验证测试 (AC: Then #3) - [x] 测试不能激活已确认/进行中/已完成状态的订单 - [x] 测试不能关闭草稿/已确认/已完成状态的订单 - [x] 验证按钮禁用状态 - [x] 确保所有测试通过 (AC: And) ## Dev Notes ### Epic Context **Epic 10: 订单管理 E2E 测试 (Epic C - 业务测试 Epic)** - **目标**: 测试开发者可以为订单管理功能编写完整的 E2E 测试,验证订单的 CRUD、状态流转、人员关联和附件管理功能 - **业务分组**: Epic C(业务测试 Epic) - **背景**: 订单管理是招聘系统的核心业务功能,涉及复杂表单(多选择器联动)、状态流转、人员关联等场景 - **模式**: 业务测试为主,工具包支持为辅(遵循 Epic A 成功模式) **依赖:** - Epic 1: ✅ 已完成(Select 工具基础框架) - Epic 2: ✅ 已完成(Select 工具在真实 E2E 测试中验证) - Story 10.1: ✅ 已完成(订单管理 Page Object) - Story 10.2: ✅ 已完成(订单列表查看测试) - Story 10.3: ✅ 已完成(订单搜索和筛选测试) - Story 10.4: ✅ 已完成(创建订单测试) - Story 10.5: ✅ 已完成(编辑订单测试) - Story 10.6: ✅ 已完成(删除订单测试) ### 前序 Story 情报 (Story 10.6) **从 Story 10.6 学到的经验:** 1. **Page Object 菜单操作模式**: - 编辑和删除操作都通过"打开菜单"按钮进入 - 状态流转按钮可能也在菜单中,或者在行操作按钮区域 - 需要先探索实际 UI 结构来确定按钮位置 2. **灵活的选择器策略**: - 使用正则表达式匹配多种可能的按钮名称 - 示例:`/^(确认删除|删除|确定|确认)$/` 匹配确认按钮 3. **测试隔离优化**: - 每个测试套件创建独立的测试订单 - 避免测试之间的状态干扰 - 使用时间戳确保订单名称唯一 4. **Toast 消息验证**: - 使用正则表达式匹配关键词而非精确匹配 - 示例:`/删除/` 匹配删除相关的成功消息 ### Page Object 已有功能 **订单状态常量定义** (`web/tests/e2e/pages/admin/order-management.page.ts`): ```typescript // 订单状态常量 export const ORDER_STATUS = { DRAFT: 'draft', CONFIRMED: 'confirmed', IN_PROGRESS: 'in_progress', COMPLETED: 'completed', } as const; export type OrderStatus = typeof ORDER_STATUS[keyof typeof ORDER_STATUS]; // 订单状态显示名称映射 export const ORDER_STATUS_LABELS: Record = { draft: '草稿', confirmed: '已确认', in_progress: '进行中', completed: '已完成', } as const; ``` **已有的相关方法:** | 方法 | 说明 | 状态流转测试用途 | |------|------|-----------------| | `createOrder(data)` | 创建订单 | 创建草稿订单作为测试起点 | | `editOrder(orderName, data)` | 编辑订单 | 可通过 `status` 字段修改状态(但不是真实的状态流转操作) | | `openDetailDialog(orderName)` | 打开订单详情 | 验证详情中的状态显示 | | `getOrderDetailInfo()` | 获取订单详情 | 获取当前订单状态信息 | | `openEditDialog(orderName)` | 打开编辑菜单 | 参考菜单操作模式 | ### 需要补充的 Page Object 方法 **状态流转操作方法(需要添加):** 1. **激活订单方法:** ```typescript /** * 打开激活订单确认对话框 * @param orderName 订单名称 */ async openActivateDialog(orderName: string): Promise /** * 确认激活订单 */ async confirmActivate(): Promise /** * 激活订单(完整流程) * @param orderName 订单名称 * @returns 是否成功激活 */ async activateOrder(orderName: string): Promise ``` 2. **关闭订单方法:** ```typescript /** * 打开关闭订单确认对话框 * @param orderName 订单名称 */ async openCloseDialog(orderName: string): Promise /** * 确认关闭订单 */ async confirmClose(): Promise /** * 关闭订单(完整流程) * @param orderName 订单名称 * @returns 是否成功关闭 */ async closeOrder(orderName: string): Promise ``` 3. **状态获取方法:** ```typescript /** * 获取订单的当前状态(从列表页面) * @param orderName 订单名称 * @returns 订单状态值 */ async getOrderStatus(orderName: string): Promise /** * 验证订单状态 * @param orderName 订单名称 * @param expectedStatus 期望的状态 */ async expectOrderStatus(orderName: string, expectedStatus: OrderStatus): Promise ``` 4. **按钮状态验证方法:** ```typescript /** * 检查激活按钮是否可用 * @param orderName 订单名称 * @returns 按钮是否可用 */ async isActivateButtonEnabled(orderName: string): Promise /** * 检查关闭按钮是否可用 * @param orderName 订单名称 * @returns 按钮是否可用 */ async isCloseButtonEnabled(orderName: string): Promise ``` ### 测试覆盖场景清单 **激活草稿订单:** - [ ] 创建草稿状态订单 - [ ] 打开激活确认对话框 - [ ] 确认激活操作 - [ ] 验证订单状态从草稿变为进行中 - [ ] 验证 Toast 成功消息显示 **关闭进行中订单:** - [ ] 创建并激活订单(准备进行中状态) - [ ] 打开关闭确认对话框 - [ ] 确认关闭操作 - [ ] 验证订单状态从进行中变为已完成 - [ ] 验证 Toast 成功消息显示 **状态限制验证:** - [ ] 尝试激活已确认状态的订单 → 按钮禁用或操作失败 - [ ] 尝试激活进行中状态的订单 → 按钮禁用或操作失败 - [ ] 尝试激活已完成状态的订单 → 按钮禁用或操作失败 - [ ] 尝试关闭草稿状态的订单 → 按钮禁用或操作失败 - [ ] 尝试关闭已确认状态的订单 → 按钮禁用或操作失败 - [ ] 尝试关闭已完成状态的订单 → 按钮禁用或操作失败 **状态流转图参考:** ``` 草稿 (draft) --[激活]--> 进行中 (in_progress) --[关闭]--> 已完成 (completed) ↑ [确认] (从草稿) ``` ### UI 结构探索要点 **状态流转按钮位置假设(需要验证):** 1. **在操作菜单中**(与编辑/删除类似): - 点击"打开菜单"按钮 - 菜单中可能包含"激活"、"关闭"等选项 2. **作为行操作按钮**: - 直接在订单行显示激活/关闭按钮 - 按钮可能根据订单状态显示/隐藏 3. **在详情页面中**: - 打开订单详情后显示状态操作按钮 **测试时优先探索的顺序:** 1. 先检查操作菜单中是否有状态流转选项 2. 检查行中是否有独立的激活/关闭按钮 3. 检查详情页面中的状态操作按钮 ### 项目结构对齐 **遵循 Epic 9.6 并行执行决策:** - ✅ 不使用 `test.describe.serial` - ✅ 每个测试创建独立的测试数据 - ✅ 使用时间戳确保订单名称唯一 **遵循项目的类型规范:** - ✅ 使用 TypeScript 严格模式 - ✅ 使用 `ORDER_STATUS` 和 `ORDER_STATUS_LABELS` 常量 - ✅ 状态类型使用 `OrderStatus` 类型别名 **遵循项目的测试模式:** - ✅ 使用 Playwright fixtures - ✅ 使用 Page Object 模式 - ✅ Toast 消息使用 `data-sonner-toast` 选择器 - ✅ 对话框使用 `role="dialog"` 或 `role="alertdialog"` ### Project Structure Notes **测试文件位置:** ``` web/tests/e2e/ ├── pages/admin/ │ └── order-management.page.ts (需要补充状态流转方法) └── specs/admin/ └── order-status.spec.ts (新建) ``` **与其他测试的关系:** - `order-list.spec.ts`: 验证列表中状态徽章显示 - `order-create.spec.ts`: 创建草稿订单(测试起点) - `order-edit.spec.ts`: 编辑订单(可能涉及状态修改) - `order-delete.spec.ts`: 删除订单(参考菜单操作模式) **潜在冲突:** - 状态流转测试可能创建多种状态的订单,需要确保数据隔离 - 建议使用唯一的订单名称前缀:`状态流转测试_${timestamp}` ### References **Epic 需求来源:** - [Source: _bmad-output/planning-artifacts/epics.md](epics.md) - Story 10.7 详细需求 **Page Object 现有实现:** - [Source: web/tests/e2e/pages/admin/order-management.page.ts](web/tests/e2e/pages/admin/order-management.page.ts) - 订单状态常量、订单数据接口 **前序 Story 学习:** - [Source: _bmad-output/implementation-artifacts/10-6-order-delete-tests.md](10-6-order-delete-tests.md) - 菜单操作模式、灵活选择器、测试隔离 **项目上下文:** - [Source: _bmad-output/project-context.md](project-context.md) - 技术栈、测试规范、类型系统 ## Dev Agent Record ### Agent Model Used claude-opus-4-5-20251101 ### Debug Log References 无 ### Completion Notes List 1. **Page Object 状态流转方法补充** (`web/tests/e2e/pages/admin/order-management.page.ts`): - 添加了 `openActivateDialog()` - 打开激活订单确认对话框 - 添加了 `confirmActivate()` - 确认激活订单 - 添加了 `activateOrder()` - 激活订单(完整流程) - 添加了 `openCloseDialog()` - 打开关闭订单确认对话框 - 添加了 `confirmClose()` - 确认关闭订单 - 添加了 `closeOrder()` - 关闭订单(完整流程) - 添加了 `getOrderStatus()` - 获取订单的当前状态 - 添加了 `expectOrderStatus()` - 验证订单状态 - 添加了 `checkActivateButtonEnabled()` - 检查激活按钮是否可用 - 添加了 `checkCloseButtonEnabled()` - 检查关闭按钮是否可用 2. **测试文件创建** (`web/tests/e2e/specs/admin/order-status.spec.ts`): - 10 个测试用例覆盖所有 AC 要求 - 激活草稿订单测试(3个测试) - 关闭进行中订单测试(3个测试) - 状态限制验证测试(3个测试) - 完整状态流转流程测试(1个测试) 3. **代码审查修复 (2026-01-12)**: - **HIGH #1-2**: 重构状态限制验证测试,现在显式创建和测试 IN_PROGRESS/COMPLETED 状态 - **HIGH #3**: 改进 `getOrderStatus()` 方法,跳过第一列避免匹配订单名称,增加状态徽章查找策略 - **HIGH #4**: 移除所有硬编码超时,使用 Playwright 最佳实践(waitForSelector, waitForFunction) - **HIGH #5**: 修复测试跳过逻辑,从 beforeEach 移到单个测试内部 - **MEDIUM #6**: 重命名方法:`isActivateButtonEnabled()` → `checkActivateButtonEnabled()`,`isCloseButtonEnabled()` → `checkCloseButtonEnabled()`,明确表示有副作用 - **MEDIUM #7**: 移除未使用的 `getFirstOrderName()` 辅助函数 - **MEDIUM #8**: 改进 Toast 消息验证正则:`/激活.*成功|已激活/` 和 `/关闭.*成功|已完成/` ### File List **新增文件:** - `web/tests/e2e/specs/admin/order-status.spec.ts` - 订单状态流转测试文件 **修改文件:** - `web/tests/e2e/pages/admin/order-management.page.ts` - 添加了10个状态流转相关方法 ### Change Log **2026-01-12** - 补充 Page Object 状态流转方法(10个新方法) - 创建订单状态流转测试文件 - 实现激活草稿订单测试 - 实现关闭进行中订单测试 - 实现状态限制验证测试 - 改进占位符文本过滤逻辑 - 添加错误处理和测试跳过逻辑 - 完成 10 个测试用例 ---