|
|
@@ -0,0 +1,440 @@
|
|
|
+# Story 10.6: 编写删除订单测试
|
|
|
+
|
|
|
+Status: ready-for-dev
|
|
|
+
|
|
|
+<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
|
|
|
+
|
|
|
+## Story
|
|
|
+
|
|
|
+作为测试开发者,
|
|
|
+我想要编写删除订单的 E2E 测试,
|
|
|
+以便验证订单删除功能和相关约束。
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+
|
|
|
+**Given** 编辑订单测试已通过
|
|
|
+**When** 编写删除订单测试用例
|
|
|
+**Then** 包含以下测试场景:
|
|
|
+
|
|
|
+1. **删除草稿状态订单**
|
|
|
+ - 删除草稿状态的订单
|
|
|
+ - 验证删除确认对话框显示
|
|
|
+ - 确认删除
|
|
|
+ - 验证删除成功后列表中不再显示
|
|
|
+
|
|
|
+2. **删除有关联人员的订单**
|
|
|
+ - 尝试删除已关联人员的订单
|
|
|
+ - 验证错误提示或级联删除行为
|
|
|
+ - 根据实际业务逻辑验证结果
|
|
|
+
|
|
|
+3. **取消删除**
|
|
|
+ - 点击删除按钮
|
|
|
+ - 在确认对话框中点击取消
|
|
|
+ - 验证订单未被删除
|
|
|
+
|
|
|
+**测试文件:** `web/tests/e2e/specs/admin/order-delete.spec.ts`
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+
|
|
|
+- [ ] 创建删除订单测试文件 (AC: When)
|
|
|
+ - [ ] 创建 `web/tests/e2e/specs/admin/order-delete.spec.ts`
|
|
|
+ - [ ] 导入必要的测试依赖(Playwright fixtures、OrderManagementPage)
|
|
|
+ - [ ] 配置测试文件的基本结构
|
|
|
+- [ ] 编写删除草稿订单测试 (AC: Then #1)
|
|
|
+ - [ ] 创建草稿状态的测试订单
|
|
|
+ - [ ] 测试打开删除确认对话框
|
|
|
+ - [ ] 测试确认删除操作
|
|
|
+ - [ ] 验证删除后订单不再存在于列表中
|
|
|
+ - [ ] 验证 Toast 成功消息显示
|
|
|
+- [ ] 编写删除有关联人员订单测试 (AC: Then #2)
|
|
|
+ - [ ] 创建订单并添加人员
|
|
|
+ - [ ] 测试删除有关联人员的订单
|
|
|
+ - [ ] 验证错误提示或级联删除行为
|
|
|
+ - [ ] 根据实际业务逻辑断言结果
|
|
|
+- [ ] 编写取消删除测试 (AC: Then #3)
|
|
|
+ - [ ] 创建测试订单
|
|
|
+ - [ ] 测试打开删除确认对话框
|
|
|
+ - [ ] 测试点击取消按钮
|
|
|
+ - [ ] 验证订单仍然存在于列表中
|
|
|
+- [ ] 确保所有测试通过 (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 情报 (Story 10.1-10.5)
|
|
|
+
|
|
|
+**Page Object 已有的删除功能:**
|
|
|
+
|
|
|
+`web/tests/e2e/pages/admin/order-management.page.ts` 包含以下删除相关方法:
|
|
|
+
|
|
|
+1. **打开删除确认对话框:**
|
|
|
+ ```typescript
|
|
|
+ async openDeleteDialog(orderName: string): Promise<void>
|
|
|
+ ```
|
|
|
+ - 找到订单行并点击删除按钮
|
|
|
+ - 等待确认对话框出现(`role="alertdialog"`)
|
|
|
+
|
|
|
+2. **确认删除:**
|
|
|
+ ```typescript
|
|
|
+ async confirmDelete(): Promise<void>
|
|
|
+ ```
|
|
|
+ - 点击"确认删除"按钮
|
|
|
+ - 等待对话框关闭和网络请求完成
|
|
|
+
|
|
|
+3. **取消删除:**
|
|
|
+ ```typescript
|
|
|
+ async cancelDelete(): Promise<void>
|
|
|
+ ```
|
|
|
+ - 点击删除确认对话框中的"取消"按钮
|
|
|
+ - 等待对话框关闭
|
|
|
+
|
|
|
+4. **删除订单完整流程:**
|
|
|
+ ```typescript
|
|
|
+ async deleteOrder(orderName: string): Promise<boolean>
|
|
|
+ ```
|
|
|
+ - 组合方法:打开对话框 → 确认删除 → 检查 Toast 消息
|
|
|
+ - 返回是否成功删除(基于 Toast 消息)
|
|
|
+
|
|
|
+5. **验证订单存在:**
|
|
|
+ ```typescript
|
|
|
+ async orderExists(orderName: string): Promise<boolean>
|
|
|
+ ```
|
|
|
+ - 检查订单是否存在于列表中
|
|
|
+
|
|
|
+6. **创建订单:**
|
|
|
+ ```typescript
|
|
|
+ async createOrder(data: OrderData): Promise<FormSubmitResult>
|
|
|
+ ```
|
|
|
+ - 用于创建测试数据
|
|
|
+
|
|
|
+### 测试数据策略
|
|
|
+
|
|
|
+**创建测试订单:**
|
|
|
+删除测试需要先有可删除的订单。参考 Story 10.3、10.4、10.5 的测试数据策略:
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 使用时间戳创建唯一订单名称
|
|
|
+const timestamp = Date.now();
|
|
|
+const testOrderName = `删除测试订单_${timestamp}`;
|
|
|
+
|
|
|
+// 先创建订单
|
|
|
+await orderManagementPage.createOrder({
|
|
|
+ name: testOrderName,
|
|
|
+ expectedStartDate: '2025-01-15',
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+**创建有关联人员的订单(测试场景 2):**
|
|
|
+```typescript
|
|
|
+// 创建订单并添加人员
|
|
|
+await orderManagementPage.createOrder({
|
|
|
+ name: testOrderName,
|
|
|
+ expectedStartDate: '2025-01-15',
|
|
|
+});
|
|
|
+
|
|
|
+// 打开人员管理对话框
|
|
|
+await orderManagementPage.openPersonManagementDialog(testOrderName);
|
|
|
+
|
|
|
+// 添加人员
|
|
|
+await orderManagementPage.addPersonToOrder({
|
|
|
+ disabledPersonName: '测试人员',
|
|
|
+ hireDate: '2025-01-20',
|
|
|
+ salary: 5000,
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### 测试文件结构参考
|
|
|
+
|
|
|
+参考 Story 10.4(创建订单测试)和 Story 10.5(编辑订单测试)的测试结构:
|
|
|
+
|
|
|
+```typescript
|
|
|
+import { test, expect } from '../../utils/test-setup';
|
|
|
+import { OrderManagementPage } from '../../pages/admin/order-management.page';
|
|
|
+import { ORDER_STATUS } from '../../pages/admin/order-management.page';
|
|
|
+
|
|
|
+test.describe.serial('删除订单测试', () => {
|
|
|
+ let testOrderName: string;
|
|
|
+
|
|
|
+ test.beforeEach(async ({ adminLoginPage, orderManagementPage }) => {
|
|
|
+ await adminLoginPage.goto();
|
|
|
+ await adminLoginPage.login('admin', 'admin123');
|
|
|
+ await orderManagementPage.goto();
|
|
|
+
|
|
|
+ // 创建测试订单
|
|
|
+ const timestamp = Date.now();
|
|
|
+ testOrderName = `删除测试_${timestamp}`;
|
|
|
+ await orderManagementPage.createOrder({
|
|
|
+ name: testOrderName,
|
|
|
+ expectedStartDate: '2025-01-15',
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ test.describe('删除草稿状态订单', () => {
|
|
|
+ test('应该成功删除草稿订单', async ({ orderManagementPage }) => {
|
|
|
+ // 打开删除确认对话框
|
|
|
+ await orderManagementPage.openDeleteDialog(testOrderName);
|
|
|
+
|
|
|
+ // 确认删除
|
|
|
+ await orderManagementPage.confirmDelete();
|
|
|
+
|
|
|
+ // 验证订单不再存在
|
|
|
+ expect(await orderManagementPage.orderExists(testOrderName)).toBe(false);
|
|
|
+ });
|
|
|
+
|
|
|
+ test('应该在删除后显示成功提示', async ({ orderManagementPage }) => {
|
|
|
+ await orderManagementPage.deleteOrder(testOrderName);
|
|
|
+
|
|
|
+ // 验证 Toast 成功消息
|
|
|
+ const successToast = orderManagementPage.page.locator('[data-sonner-toast][data-type="success"]');
|
|
|
+ await expect(successToast).toBeVisible();
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ test.describe('取消删除', () => {
|
|
|
+ test('应该能在确认对话框中取消删除', async ({ orderManagementPage }) => {
|
|
|
+ // 打开删除确认对话框
|
|
|
+ await orderManagementPage.openDeleteDialog(testOrderName);
|
|
|
+
|
|
|
+ // 取消删除
|
|
|
+ await orderManagementPage.cancelDelete();
|
|
|
+
|
|
|
+ // 验证订单仍然存在
|
|
|
+ expect(await orderManagementPage.orderExists(testOrderName)).toBe(true);
|
|
|
+ });
|
|
|
+ });
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### 技术要求
|
|
|
+
|
|
|
+**导入依赖:**
|
|
|
+```typescript
|
|
|
+import { test, expect } from '../../utils/test-setup';
|
|
|
+import { OrderManagementPage, ORDER_STATUS } from '../../pages/admin/order-management.page';
|
|
|
+```
|
|
|
+
|
|
|
+**测试 Fixtures:**
|
|
|
+- 使用 `adminLoginPage` fixture 进行登录
|
|
|
+- 使用 `orderManagementPage` fixture 操作页面
|
|
|
+- 使用 `test.describe.serial()` 确保测试按顺序执行
|
|
|
+
|
|
|
+**断言策略:**
|
|
|
+- 验证删除确认对话框正确显示
|
|
|
+- 验证删除后订单不再存在于列表中
|
|
|
+- 验证 Toast 成功/错误消息显示
|
|
|
+- 对于有关联人员的订单,根据实际业务逻辑验证结果
|
|
|
+
|
|
|
+### 业务逻辑说明
|
|
|
+
|
|
|
+**删除订单的业务规则(需要验证):**
|
|
|
+
|
|
|
+1. **草稿状态订单**:
|
|
|
+ - 应该可以直接删除
|
|
|
+ - 删除后订单从列表中移除
|
|
|
+ - 显示成功提示消息
|
|
|
+
|
|
|
+2. **有关联人员的订单**:
|
|
|
+ - **场景 A - 禁止删除**: 显示错误提示,不允许删除
|
|
|
+ - **场景 B - 级联删除**: 删除订单及其关联的人员数据
|
|
|
+ - **需要根据实际业务逻辑实现对应测试**
|
|
|
+
|
|
|
+3. **删除确认对话框**:
|
|
|
+ - 使用 `role="alertdialog"` 定位
|
|
|
+ - 包含"确认删除"和"取消"按钮
|
|
|
+ - 点击取消后订单保持不变
|
|
|
+
|
|
|
+### 测试标准参考
|
|
|
+
|
|
|
+遵循以下测试标准文档:
|
|
|
+- `docs/standards/testing-standards.md` - 测试规范
|
|
|
+- `docs/standards/web-ui-testing-standards.md` - Web UI 测试规范
|
|
|
+- `docs/standards/e2e-radix-testing.md` - Radix UI E2E 测试标准
|
|
|
+
|
|
|
+**选择器优先级:**
|
|
|
+1. `data-testid` - 最高优先级
|
|
|
+2. `aria-label + role`
|
|
|
+3. `text content + role` - 兜底
|
|
|
+
|
|
|
+### Project Structure Notes
|
|
|
+
|
|
|
+**文件位置:**
|
|
|
+- 测试文件: `web/tests/e2e/specs/admin/order-delete.spec.ts`
|
|
|
+- Page Object: `web/tests/e2e/pages/admin/order-management.page.ts`
|
|
|
+- Fixtures 目录: `web/tests/e2e/fixtures/`
|
|
|
+
|
|
|
+**对齐统一项目结构:**
|
|
|
+- 遵循 `project-context.md` 中的 TypeScript 严格模式规则
|
|
|
+- 函数参数、返回值必须有明确类型注解
|
|
|
+- 禁止使用 `any` 类型
|
|
|
+- 公共 API 必须包含完整 JSDoc 注释
|
|
|
+
|
|
|
+### 测试运行命令
|
|
|
+
|
|
|
+```bash
|
|
|
+# 在 web 目录下运行单个测试文件
|
|
|
+cd web
|
|
|
+pnpm test:e2e:chromium order-delete
|
|
|
+
|
|
|
+# 快速失败模式(推荐调试时使用)
|
|
|
+timeout 60 pnpm test:e2e:chromium order-delete
|
|
|
+```
|
|
|
+
|
|
|
+### 测试注意事项
|
|
|
+
|
|
|
+**删除确认对话框交互:**
|
|
|
+- 删除按钮可能通过操作菜单访问(参考 Story 10.5 经验)
|
|
|
+- 需要先点击"打开菜单"按钮,再点击"删除"选项
|
|
|
+- 确认对话框使用 `role="alertdialog"` 定位
|
|
|
+
|
|
|
+**测试数据清理:**
|
|
|
+- 删除测试会实际删除数据
|
|
|
+- 每个测试应创建独立的测试订单
|
|
|
+- 使用时间戳确保订单名称唯一
|
|
|
+
|
|
|
+**断言策略:**
|
|
|
+- 验证 `confirmDelete()` 后列表中订单消失
|
|
|
+- 验证 `cancelDelete()` 后订单仍然存在
|
|
|
+- 验证 Toast 成功消息显示(用于删除操作)
|
|
|
+- 验证 Toast 错误消息显示(用于删除失败场景)
|
|
|
+
|
|
|
+**有关联人员订单的测试:**
|
|
|
+- 需要先创建订单并添加人员
|
|
|
+- 根据实际业务逻辑:
|
|
|
+ - 如果禁止删除:验证错误消息显示
|
|
|
+ - 如果允许删除:验证级联删除成功
|
|
|
+- 可能需要先查看后端 API 或 UI 行为确定业务规则
|
|
|
+
|
|
|
+### 测试覆盖场景清单
|
|
|
+
|
|
|
+**删除草稿状态订单:**
|
|
|
+- [ ] 打开删除确认对话框
|
|
|
+- [ ] 确认删除操作
|
|
|
+- [ ] 验证删除后列表中不再显示该订单
|
|
|
+- [ ] 验证 Toast 成功消息显示
|
|
|
+
|
|
|
+**删除有关联人员的订单:**
|
|
|
+- [ ] 创建订单并添加人员
|
|
|
+- [ ] 尝试删除有关联人员的订单
|
|
|
+- [ ] 验证错误提示或级联删除行为(根据实际业务逻辑)
|
|
|
+
|
|
|
+**取消删除:**
|
|
|
+- [ ] 打开删除确认对话框
|
|
|
+- [ ] 点击取消按钮
|
|
|
+- [ ] 验证订单仍然存在于列表中
|
|
|
+
|
|
|
+**边界条件测试(可选):**
|
|
|
+- [ ] 删除不存在的订单
|
|
|
+- [ ] 删除已完成状态的订单
|
|
|
+- [ ] 并发删除同一订单
|
|
|
+
|
|
|
+### 前序 Story 经验总结 (Story 10.2, 10.3, 10.4, 10.5)
|
|
|
+
|
|
|
+**从 Story 10.2(订单列表测试)学到的经验:**
|
|
|
+- 列表表格使用 `table tbody tr` 选择器定位行
|
|
|
+- 订单状态徽章使用 `getByText` 精确匹配
|
|
|
+- 工作状态徽章使用 `getByText` 精确匹配
|
|
|
+
|
|
|
+**从 Story 10.3(订单筛选测试)学到的经验:**
|
|
|
+- 对标签使用 `locator('label').filter({ hasText: ... })` 避免与表头冲突
|
|
|
+- 对操作添加 `waitForLoadState` 超时处理(可能不触发网络请求)
|
|
|
+- 使用 `selectRadixOption` 工具选择下拉选项
|
|
|
+- 日期处理使用本地时间格式
|
|
|
+
|
|
|
+**从 Story 10.4(创建订单测试)学到的经验:**
|
|
|
+- 使用 `createOrder()` 方法创建测试数据
|
|
|
+- 测试数据使用时间戳确保唯一性
|
|
|
+- 验证 Toast 消息确认操作结果
|
|
|
+
|
|
|
+**从 Story 10.5(编辑订单测试)学到的关键经验:**
|
|
|
+
|
|
|
+1. **订单操作菜单问题**: 编辑按钮不是直接在表格中,而是需要先点击"打开菜单"按钮才能看到编辑选项。删除操作可能也是类似的模式。
|
|
|
+
|
|
|
+2. **删除按钮位置**: 检查删除按钮是否也在操作菜单中,如果是,需要:
|
|
|
+ ```typescript
|
|
|
+ // 找到订单行并点击"打开菜单"按钮
|
|
|
+ const orderRow = this.orderTable.locator('tbody tr').filter({ hasText: orderName });
|
|
|
+ const menuButton = orderRow.getByRole('button', { name: '打开菜单' });
|
|
|
+ await menuButton.click();
|
|
|
+
|
|
|
+ // 等待菜单出现并点击"删除"选项
|
|
|
+ const deleteOption = this.page.getByRole('menuitem', { name: '删除' });
|
|
|
+ await deleteOption.click();
|
|
|
+ ```
|
|
|
+
|
|
|
+3. **网络等待超时问题**: `waitForLoadState('networkidle')` 可能超时,使用 try-catch 包裹处理。
|
|
|
+
|
|
|
+4. **测试数据管理**: 每个测试创建独立的测试订单,避免数据冲突。
|
|
|
+
|
|
|
+### 关键代码模式
|
|
|
+
|
|
|
+**订单数据接口:**
|
|
|
+```typescript
|
|
|
+interface OrderData {
|
|
|
+ name: string;
|
|
|
+ expectedStartDate?: string;
|
|
|
+ platformId?: number;
|
|
|
+ platformName?: string;
|
|
|
+ companyId?: number;
|
|
|
+ companyName?: string;
|
|
|
+ channelId?: number;
|
|
|
+ channelName?: string;
|
|
|
+ status?: OrderStatus;
|
|
|
+ workStatus?: WorkStatus;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**订单人员数据接口:**
|
|
|
+```typescript
|
|
|
+interface OrderPersonData {
|
|
|
+ disabledPersonId: number;
|
|
|
+ disabledPersonName?: string;
|
|
|
+ hireDate?: string;
|
|
|
+ salary?: number;
|
|
|
+ workStatus?: WorkStatus;
|
|
|
+ actualHireDate?: string;
|
|
|
+ resignDate?: string;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### References
|
|
|
+
|
|
|
+- [Source: _bmad-output/planning-artifacts/epics.md#Story 10.6](../planning-artifacts/epics.md)
|
|
|
+- [Source: _bmad-output/planning-artifacts/prd.md](../planning-artifacts/prd.md)
|
|
|
+- [Source: _bmad-output/planning-artifacts/architecture.md](../planning-artifacts/architecture.md)
|
|
|
+- [Source: web/tests/e2e/pages/admin/order-management.page.ts](../../web/tests/e2e/pages/admin/order-management.page.ts)
|
|
|
+- [Source: _bmad-output/implementation-artifacts/10-1-order-page-object.md](10-1-order-page-object.md)
|
|
|
+- [Source: _bmad-output/implementation-artifacts/10-2-order-list-tests.md](10-2-order-list-tests.md)
|
|
|
+- [Source: _bmad-output/implementation-artifacts/10-3-order-filter-tests.md](10-3-order-filter-tests.md)
|
|
|
+- [Source: _bmad-output/implementation-artifacts/10-4-order-create-tests.md](10-4-order-create-tests.md)
|
|
|
+- [Source: _bmad-output/implementation-artifacts/10-5-order-edit-tests.md](10-5-order-edit-tests.md)
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+
|
|
|
+claude-opus-4-5-20251101
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+
|
|
|
+### File List
|
|
|
+
|
|
|
+---
|