|
|
@@ -0,0 +1,625 @@
|
|
|
+# Story 11.9: 配置数据验证(订单可以选择平台和公司)
|
|
|
+
|
|
|
+Status: ready-for-dev
|
|
|
+
|
|
|
+<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
|
|
|
+
|
|
|
+## Story
|
|
|
+
|
|
|
+作为测试开发者,
|
|
|
+我想要验证订单可以选择平台和公司配置数据,
|
|
|
+以便确保 Epic 11 的配置管理测试为后续的订单管理测试提供稳定的测试数据基础。
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+
|
|
|
+1. **AC1: 创建测试文件**
|
|
|
+ - 文件路径: `web/tests/e2e/specs/admin/order-config-validation.spec.ts`
|
|
|
+ - 使用 Playwright test 框架
|
|
|
+ - 使用现有的 `OrderManagementPage` Page Object
|
|
|
+ - 定义测试夹具(fixtures)包含 Page Object
|
|
|
+
|
|
|
+2. **AC2: 验证订单可以选择平台**
|
|
|
+ - 首先创建测试用的平台数据
|
|
|
+ - 打开创建订单对话框
|
|
|
+ - 使用 `selectRadixOptionAsync` 选择平台
|
|
|
+ - 验证平台选项正确显示
|
|
|
+ - 验证选择成功
|
|
|
+
|
|
|
+3. **AC3: 验证订单可以选择公司**
|
|
|
+ - 首先创建测试用的平台和公司数据
|
|
|
+ - 打开创建订单对话框
|
|
|
+ - 使用 `selectRadixOptionAsync` 选择公司
|
|
|
+ - 验证公司选项正确显示(可能需要先选择平台)
|
|
|
+ - 验证选择成功
|
|
|
+
|
|
|
+4. **AC4: 验证平台和公司的关联关系**
|
|
|
+ - 创建测试平台和关联的公司
|
|
|
+ - 验证选择平台后,公司选项包含该平台下的公司
|
|
|
+ - 验证不选择平台时也能选择公司(如适用)
|
|
|
+
|
|
|
+5. **AC5: 验证配置数据在订单列表中正确显示**
|
|
|
+ - 创建包含平台和公司的订单
|
|
|
+ - 验证订单列表正确显示平台和公司信息
|
|
|
+ - 验证订单详情正确显示配置数据
|
|
|
+
|
|
|
+6. **AC6: 测试数据清理**
|
|
|
+ - 每个测试用例结束后清理创建的测试数据
|
|
|
+ - 先删除订单,再删除公司,最后删除平台(遵循外键依赖顺序)
|
|
|
+ - 验证清理成功
|
|
|
+
|
|
|
+7. **AC7: 代码质量标准**
|
|
|
+ - TypeScript 类型检查通过(无类型错误)
|
|
|
+ - 测试用例有清晰的描述
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+
|
|
|
+- [ ] 任务 1: 创建测试文件和基础结构 (AC: 1, 7)
|
|
|
+ - [ ] 创建文件 `web/tests/e2e/specs/admin/order-config-validation.spec.ts`
|
|
|
+ - [ ] 导入 Playwright test 和 OrderManagementPage
|
|
|
+ - [ ] 导入 PlatformManagementPage 和 CompanyManagementPage(用于创建测试数据)
|
|
|
+ - [ ] 定义测试夹具(adminLoginPage, orderManagementPage, platformManagementPage, companyManagementPage)
|
|
|
+ - [ ] 设置测试基础配置
|
|
|
+
|
|
|
+- [ ] 任务 2: 实现测试前置条件 (AC: 1, 2)
|
|
|
+ - [ ] 实现 `test.beforeEach()` 登录后台
|
|
|
+ - [ ] 导航到订单管理页面
|
|
|
+ - [ ] 验证页面加载完成
|
|
|
+
|
|
|
+- [ ] 任务 3: 实现订单选择平台验证 (AC: 2, 6)
|
|
|
+ - [ ] 编写测试用例:应该成功选择平台
|
|
|
+ - [ ] 使用 PlatformManagementPage 创建测试平台
|
|
|
+ - [ ] 打开创建订单对话框
|
|
|
+ - [ ] 使用 `selectRadixOptionAsync` 选择平台
|
|
|
+ - [ ] 验证选择成功
|
|
|
+ - [ ] 清理测试数据
|
|
|
+
|
|
|
+- [ ] 任务 4: 实现订单选择公司验证 (AC: 3, 6)
|
|
|
+ - [ ] 编写测试用例:应该成功选择公司
|
|
|
+ - [ ] 使用 CompanyManagementPage 创建测试公司(需要先有平台)
|
|
|
+ - [ ] 打开创建订单对话框
|
|
|
+ - [ ] 使用 `selectRadixOptionAsync` 选择公司
|
|
|
+ - [ ] 验证选择成功
|
|
|
+ - [ ] 清理测试数据(订单→公司→平台)
|
|
|
+
|
|
|
+- [ ] 任务 5: 实现平台公司关联关系验证 (AC: 4, 6)
|
|
|
+ - [ ] 编写测试用例:应该验证平台与公司的关联
|
|
|
+ - [ ] 创建平台和多个关联公司
|
|
|
+ - [ ] 验证公司选项包含正确的公司
|
|
|
+ - [ ] 清理测试数据
|
|
|
+
|
|
|
+- [ ] 任务 6: 实现订单列表配置数据显示验证 (AC: 5, 6)
|
|
|
+ - [ ] 编写测试用例:订单列表应正确显示平台和公司
|
|
|
+ - [ ] 创建包含平台和公司的测试订单
|
|
|
+ - [ ] 验证订单列表显示正确的平台和公司信息
|
|
|
+ - [ ] 验证订单详情显示正确的配置数据
|
|
|
+ - [ ] 清理测试数据
|
|
|
+
|
|
|
+- [ ] 任务 7: 实现测试后清理 (AC: 6)
|
|
|
+ - [ ] 每个测试用例内清理测试数据
|
|
|
+ - [ ] 遵循正确的删除顺序:订单→公司→平台
|
|
|
+ - [ ] 验证清理成功
|
|
|
+
|
|
|
+- [ ] 任务 8: 运行测试并验证 (AC: 2, 3, 4, 5, 6, 7)
|
|
|
+ - [ ] 运行测试: `pnpm test:e2e:chromium order-config-validation`
|
|
|
+ - [ ] TypeScript 类型检查通过
|
|
|
+ - [ ] 修复发现的问题
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### Epic 11 背景和目标
|
|
|
+
|
|
|
+**Epic 11: 基础配置管理测试 (Epic F)**
|
|
|
+
|
|
|
+为平台、公司、渠道配置管理编写 E2E 测试,为后续用户管理和跨端测试提供必要的测试数据。
|
|
|
+
|
|
|
+**实体关系链:**
|
|
|
+```
|
|
|
+Platform (平台)
|
|
|
+ ↓ 1:N
|
|
|
+Company (公司) - 必须 platformId
|
|
|
+ ↓ 1:N
|
|
|
+Order (订单) - 必须 companyId
|
|
|
+ ↓
|
|
|
+Channel (渠道) - 订单的可选条件
|
|
|
+```
|
|
|
+
|
|
|
+**Story 11.9 在 Epic 中的位置:**
|
|
|
+- 这是 Epic 11 的最后一个 Story
|
|
|
+- 验证前面创建的配置管理功能(Platform、Company)可以被订单正确使用
|
|
|
+- 为后续的订单管理测试(Epic 10)提供配置数据验证
|
|
|
+
|
|
|
+### 架构模式和约束
|
|
|
+
|
|
|
+**测试文件结构参考:**
|
|
|
+
|
|
|
+参考 Story 11.2(平台创建测试)和 Story 11.5(公司创建测试)的结构模式:
|
|
|
+- `web/tests/e2e/specs/admin/order-config-validation.spec.ts`(当前)
|
|
|
+
|
|
|
+**标准测试文件结构:**
|
|
|
+```typescript
|
|
|
+import { test, expect } from '@playwright/test';
|
|
|
+import { OrderManagementPage } from '../../pages/admin/order-management.page';
|
|
|
+import { PlatformManagementPage } from '../../pages/admin/platform-management.page';
|
|
|
+import { CompanyManagementPage } from '../../pages/admin/company-management.page';
|
|
|
+
|
|
|
+test.describe('订单配置数据验证', () => {
|
|
|
+ test.beforeEach(async ({ adminLoginPage, orderManagementPage }) => {
|
|
|
+ // 登录后台
|
|
|
+ await adminLoginPage.goto();
|
|
|
+ await adminLoginPage.login('admin', 'admin123');
|
|
|
+
|
|
|
+ // 导航到订单管理页面
|
|
|
+ await orderManagementPage.goto();
|
|
|
+ });
|
|
|
+
|
|
|
+ test.afterEach(async ({ platformManagementPage, companyManagementPage, orderManagementPage }) => {
|
|
|
+ // 清理测试数据:订单→公司→平台
|
|
|
+ });
|
|
|
+
|
|
|
+ test('应该成功选择平台', async ({ orderManagementPage, platformManagementPage }) => {
|
|
|
+ // 测试逻辑
|
|
|
+ });
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+**测试夹具配置:**
|
|
|
+
|
|
|
+需要在 `web/tests/e2e/utils/test-setup.ts` 确认以下 fixtures 已添加:
|
|
|
+```typescript
|
|
|
+export const test = test.extend<{
|
|
|
+ adminLoginPage: AdminLoginPage;
|
|
|
+ orderManagementPage: OrderManagementPage;
|
|
|
+ platformManagementPage: PlatformManagementPage;
|
|
|
+ companyManagementPage: CompanyManagementPage;
|
|
|
+}>({
|
|
|
+ adminLoginPage: async ({ page }, use) => {
|
|
|
+ await use(new AdminLoginPage(page));
|
|
|
+ },
|
|
|
+ orderManagementPage: async ({ page }, use) => {
|
|
|
+ await use(new OrderManagementPage(page));
|
|
|
+ },
|
|
|
+ platformManagementPage: async ({ page }, use) => {
|
|
|
+ await use(new PlatformManagementPage(page));
|
|
|
+ },
|
|
|
+ companyManagementPage: async ({ page }, use) => {
|
|
|
+ await use(new CompanyManagementPage(page));
|
|
|
+ },
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### OrderManagementPage API 参考
|
|
|
+
|
|
|
+**相关方法:**
|
|
|
+
|
|
|
+| 方法 | 描述 | 返回值 |
|
|
|
+|------|------|--------|
|
|
|
+| `goto()` | 导航到订单管理页面 | `Promise<void>` |
|
|
|
+| `openCreateDialog()` | 打开创建订单对话框 | `Promise<void>` |
|
|
|
+| `fillOrderForm(data)` | 填写订单表单 | `Promise<void>` |
|
|
|
+| `createOrder(data)` | 创建订单(完整流程) | `Promise<FormSubmitResult>` |
|
|
|
+| `orderExists(name)` | 验证订单是否存在 | `Promise<boolean>` |
|
|
|
+| `deleteOrder(name)` | 删除订单 | `Promise<boolean>` |
|
|
|
+
|
|
|
+**数据接口:**
|
|
|
+```typescript
|
|
|
+interface OrderData {
|
|
|
+ name: string; // 订单名称(必填)
|
|
|
+ expectedStartDate?: string; // 预计开始日期
|
|
|
+ platformName?: string; // 平台名称
|
|
|
+ companyName?: string; // 公司名称
|
|
|
+ channelName?: string; // 渠道名称
|
|
|
+ status?: OrderStatus; // 订单状态
|
|
|
+ workStatus?: WorkStatus; // 工作状态
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 创建订单表单分析
|
|
|
+
|
|
|
+**订单创建对话框字段(来自 OrderManagement.tsx):**
|
|
|
+
|
|
|
+1. **name** - Input(必填)
|
|
|
+ - 占位符: "订单名称" 或类似
|
|
|
+ - 需要确认实际的 data-testid
|
|
|
+
|
|
|
+2. **platformId** - PlatformSelector(异步)
|
|
|
+ - 使用 Radix UI Select 组件
|
|
|
+ - 异步加载平台选项
|
|
|
+ - 标签: "平台"
|
|
|
+ - 需要使用 `selectRadixOptionAsync` 选择
|
|
|
+
|
|
|
+3. **companyId** - CompanySelector(异步)
|
|
|
+ - 使用 Radix UI Select 组件
|
|
|
+ - 异步加载公司选项
|
|
|
+ - 标签: "公司"
|
|
|
+ - 需要使用 `selectRadixOptionAsync` 选择
|
|
|
+ - 可能需要先选择平台(取决于业务逻辑)
|
|
|
+
|
|
|
+4. **expectedStartDate** - DateInput(可选)
|
|
|
+ - 标签: "预计开始日期" 或 "开始日期"
|
|
|
+
|
|
|
+**按钮:**
|
|
|
+- 取消按钮
|
|
|
+- 提交按钮: "创建" 或类似
|
|
|
+
|
|
|
+### 测试用例设计
|
|
|
+
|
|
|
+**测试用例 1: 验证订单可以选择平台**
|
|
|
+```typescript
|
|
|
+test('应该成功选择平台', async ({ orderManagementPage, platformManagementPage }) => {
|
|
|
+ const timestamp = Date.now();
|
|
|
+
|
|
|
+ // 创建测试平台
|
|
|
+ const platformName = `测试平台_${timestamp}`;
|
|
|
+ await platformManagementPage.createPlatform({
|
|
|
+ platformName,
|
|
|
+ contactPerson: '测试联系人',
|
|
|
+ contactPhone: '13800138000'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 打开创建订单对话框
|
|
|
+ await orderManagementPage.openCreateDialog();
|
|
|
+
|
|
|
+ // 选择平台
|
|
|
+ await selectRadixOptionAsync(orderManagementPage.page, '平台', platformName);
|
|
|
+
|
|
|
+ // 填写订单名称
|
|
|
+ await orderManagementPage.page.getByLabel(/订单名称|名称/).fill(`测试订单_${timestamp}`);
|
|
|
+
|
|
|
+ // 提交表单
|
|
|
+ const result = await orderManagementPage.submitForm();
|
|
|
+ expect(result.success).toBe(true);
|
|
|
+
|
|
|
+ // 清理
|
|
|
+ await orderManagementPage.waitForDialogClosed();
|
|
|
+ await orderManagementPage.deleteOrder(`测试订单_${timestamp}`);
|
|
|
+ await platformManagementPage.deletePlatform(platformName);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+**测试用例 2: 验证订单可以选择公司**
|
|
|
+```typescript
|
|
|
+test('应该成功选择公司', async ({ orderManagementPage, platformManagementPage, companyManagementPage }) => {
|
|
|
+ const timestamp = Date.now();
|
|
|
+
|
|
|
+ // 创建测试平台
|
|
|
+ const platformName = `测试平台_${timestamp}`;
|
|
|
+ await platformManagementPage.createPlatform({
|
|
|
+ platformName
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建测试公司
|
|
|
+ const companyName = `测试公司_${timestamp}`;
|
|
|
+ await companyManagementPage.createCompany({
|
|
|
+ companyName
|
|
|
+ }, platformName);
|
|
|
+
|
|
|
+ // 打开创建订单对话框
|
|
|
+ await orderManagementPage.openCreateDialog();
|
|
|
+
|
|
|
+ // 选择公司
|
|
|
+ await selectRadixOptionAsync(orderManagementPage.page, '公司', companyName);
|
|
|
+
|
|
|
+ // 填写订单名称
|
|
|
+ await orderManagementPage.page.getByLabel(/订单名称|名称/).fill(`测试订单_${timestamp}`);
|
|
|
+
|
|
|
+ // 提交表单
|
|
|
+ const result = await orderManagementPage.submitForm();
|
|
|
+ expect(result.success).toBe(true);
|
|
|
+
|
|
|
+ // 清理
|
|
|
+ await orderManagementPage.waitForDialogClosed();
|
|
|
+ await orderManagementPage.deleteOrder(`测试订单_${timestamp}`);
|
|
|
+ await companyManagementPage.deleteCompany(companyName);
|
|
|
+ await platformManagementPage.deletePlatform(platformName);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+**测试用例 3: 验证平台和公司关联关系**
|
|
|
+```typescript
|
|
|
+test('应该验证平台与公司的关联', async ({ orderManagementPage, platformManagementPage, companyManagementPage }) => {
|
|
|
+ const timestamp = Date.now();
|
|
|
+
|
|
|
+ // 创建测试平台
|
|
|
+ const platformName = `测试平台_${timestamp}`;
|
|
|
+ await platformManagementPage.createPlatform({ platformName });
|
|
|
+
|
|
|
+ // 创建多个关联公司
|
|
|
+ const company1Name = `测试公司1_${timestamp}`;
|
|
|
+ const company2Name = `测试公司2_${timestamp}`;
|
|
|
+ await companyManagementPage.createCompany({ companyName: company1Name }, platformName);
|
|
|
+ await companyManagementPage.createCompany({ companyName: company2Name }, platformName);
|
|
|
+
|
|
|
+ // 打开创建订单对话框
|
|
|
+ await orderManagementPage.openCreateDialog();
|
|
|
+
|
|
|
+ // 验证公司选项包含创建的公司
|
|
|
+ // (需要根据实际 UI 实现调整验证逻辑)
|
|
|
+
|
|
|
+ // 清理
|
|
|
+ await orderManagementPage.cancelDialog();
|
|
|
+ await companyManagementPage.deleteCompany(company1Name);
|
|
|
+ await companyManagementPage.deleteCompany(company2Name);
|
|
|
+ await platformManagementPage.deletePlatform(platformName);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+**测试用例 4: 验证订单列表显示配置数据**
|
|
|
+```typescript
|
|
|
+test('订单列表应正确显示平台和公司', async ({ orderManagementPage, platformManagementPage, companyManagementPage }) => {
|
|
|
+ const timestamp = Date.now();
|
|
|
+
|
|
|
+ // 创建测试配置数据
|
|
|
+ const platformName = `测试平台_${timestamp}`;
|
|
|
+ const companyName = `测试公司_${timestamp}`;
|
|
|
+ const orderName = `测试订单_${timestamp}`;
|
|
|
+
|
|
|
+ await platformManagementPage.createPlatform({ platformName });
|
|
|
+ await companyManagementPage.createCompany({ companyName }, platformName);
|
|
|
+
|
|
|
+ // 创建包含配置数据的订单
|
|
|
+ await orderManagementPage.createOrder({
|
|
|
+ name: orderName,
|
|
|
+ platformName,
|
|
|
+ companyName
|
|
|
+ });
|
|
|
+
|
|
|
+ // 验证订单列表显示正确的平台和公司信息
|
|
|
+ const orderExists = await orderManagementPage.orderExists(orderName);
|
|
|
+ expect(orderExists).toBe(true);
|
|
|
+
|
|
|
+ // 验证订单详情显示配置数据
|
|
|
+ await orderManagementPage.openDetailDialog(orderName);
|
|
|
+ const detailInfo = await orderManagementPage.getOrderDetailInfo();
|
|
|
+ expect(detailInfo.platform).toBe(platformName);
|
|
|
+ expect(detailInfo.company).toBe(companyName);
|
|
|
+
|
|
|
+ // 清理
|
|
|
+ await orderManagementPage.closeDetailDialog();
|
|
|
+ await orderManagementPage.deleteOrder(orderName);
|
|
|
+ await companyManagementPage.deleteCompany(companyName);
|
|
|
+ await platformManagementPage.deletePlatform(platformName);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### 数据清理策略
|
|
|
+
|
|
|
+**遵循外键依赖顺序:**
|
|
|
+```
|
|
|
+订单 → 公司 → 平台
|
|
|
+```
|
|
|
+
|
|
|
+**原因:**
|
|
|
+- 订单依赖公司(companyId 外键)
|
|
|
+- 公司依赖平台(platformId 外键)
|
|
|
+- 必须先删除子级,再删除父级
|
|
|
+
|
|
|
+**清理示例:**
|
|
|
+```typescript
|
|
|
+test.afterEach(async ({ orderManagementPage, companyManagementPage, platformManagementPage }) => {
|
|
|
+ // 按相反顺序清理
|
|
|
+ if (orderName) {
|
|
|
+ await orderManagementPage.deleteOrder(orderName);
|
|
|
+ }
|
|
|
+ if (companyName) {
|
|
|
+ await companyManagementPage.deleteCompany(companyName);
|
|
|
+ }
|
|
|
+ if (platformName) {
|
|
|
+ await platformManagementPage.deletePlatform(platformName);
|
|
|
+ }
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### PlatformSelector 和 CompanySelector 集成要点
|
|
|
+
|
|
|
+**使用 `@d8d/e2e-test-utils` 的 `selectRadixOptionAsync`:**
|
|
|
+```typescript
|
|
|
+import { selectRadixOptionAsync } from '@d8d/e2e-test-utils';
|
|
|
+
|
|
|
+// 选择平台
|
|
|
+await selectRadixOptionAsync(orderManagementPage.page, '平台', platformName);
|
|
|
+
|
|
|
+// 选择公司
|
|
|
+await selectRadixOptionAsync(orderManagementPage.page, '公司', companyName);
|
|
|
+```
|
|
|
+
|
|
|
+**异步加载等待:**
|
|
|
+- 平台和公司选项都是异步加载的
|
|
|
+- 使用 `selectRadixOptionAsync` 确保选项加载完成
|
|
|
+- 默认超时 5000ms,可以根据需要调整
|
|
|
+
|
|
|
+### 项目结构约束
|
|
|
+
|
|
|
+**测试文件存放路径:**
|
|
|
+```
|
|
|
+web/tests/e2e/
|
|
|
+├── pages/admin/
|
|
|
+│ ├── order-management.page.ts # 订单管理 Page Object(已存在)
|
|
|
+│ ├── platform-management.page.ts # 平台管理 Page Object(已存在)
|
|
|
+│ └── company-management.page.ts # 公司管理 Page Object(已存在)
|
|
|
+├── specs/admin/
|
|
|
+│ └── order-config-validation.spec.ts # 订单配置验证测试(当前)
|
|
|
+└── utils/
|
|
|
+ └── test-setup.ts # 测试夹具配置
|
|
|
+```
|
|
|
+
|
|
|
+**依赖文件:**
|
|
|
+- `web/tests/e2e/pages/admin/order-management.page.ts` - 已存在
|
|
|
+- `web/tests/e2e/pages/admin/platform-management.page.ts` - Story 11.1 创建
|
|
|
+- `web/tests/e2e/pages/admin/company-management.page.ts` - Story 11.4 创建
|
|
|
+- `web/tests/e2e/utils/test-setup.ts` - 需要确认包含所有必要的 fixtures
|
|
|
+
|
|
|
+### 测试运行命令
|
|
|
+
|
|
|
+**运行单个测试文件:**
|
|
|
+```bash
|
|
|
+cd web
|
|
|
+pnpm test:e2e:chromium order-config-validation.spec.ts
|
|
|
+```
|
|
|
+
|
|
|
+**运行单个测试用例:**
|
|
|
+```bash
|
|
|
+cd web
|
|
|
+pnpm test:e2e:chromium order-config-validation.spec.ts -g "应该成功选择平台"
|
|
|
+```
|
|
|
+
|
|
|
+**快速失败模式(调试):**
|
|
|
+```bash
|
|
|
+cd web
|
|
|
+timeout 60 pnpm test:e2e:chromium order-config-validation.spec.ts
|
|
|
+```
|
|
|
+
|
|
|
+### 依赖关系
|
|
|
+
|
|
|
+**Epic 11 内部依赖:**
|
|
|
+- Story 11.1: ✅ 已完成(PlatformManagementPage)
|
|
|
+- Story 11.2: ✅ 已完成(平台创建测试)
|
|
|
+- Story 11.4: ✅ 已完成(CompanyManagementPage)
|
|
|
+- Story 11.5: ✅ 已完成(公司创建测试)
|
|
|
+- Story 11.9: 配置数据验证(当前)
|
|
|
+
|
|
|
+**外部依赖:**
|
|
|
+- Epic 1, 2: `@d8d/e2e-test-utils` 包(已存在)
|
|
|
+- `web/tests/e2e/pages/admin/order-management.page.ts`: 已存在
|
|
|
+- `web/tests/e2e/utils/test-setup.ts`: 需要包含所有必要的 fixtures
|
|
|
+
|
|
|
+### 测试标准和规范
|
|
|
+
|
|
|
+遵循项目测试标准:
|
|
|
+- `docs/standards/testing-standards.md`
|
|
|
+- `docs/standards/web-ui-testing-standards.md`
|
|
|
+
|
|
|
+**关键测试原则:**
|
|
|
+1. 测试独立性:每个测试用例独立运行
|
|
|
+2. 数据清理:每个测试结束后清理自己创建的数据
|
|
|
+3. 清晰断言:使用 expect() 明确断言预期结果
|
|
|
+4. 等待策略:使用 Playwright 的 auto-waiting
|
|
|
+
|
|
|
+### 前序 Story (11.1-11.8) 关键经验
|
|
|
+
|
|
|
+从 Story 11.1-11.8 中学到的关键经验:
|
|
|
+
|
|
|
+1. **异步 Select 处理:**
|
|
|
+ - PlatformSelector 和 CompanySelector 都是异步加载的
|
|
|
+ - 必须使用 `selectRadixOptionAsync`
|
|
|
+ - 设置合理的超时时间(默认 5000ms)
|
|
|
+
|
|
|
+2. **测试数据要求:**
|
|
|
+ - 后端 Zod schema 要求字段类型正确
|
|
|
+ - 空字符串在某些字段中是有效值(有默认值)
|
|
|
+ - 测试不填的可选字段应该设为 undefined
|
|
|
+
|
|
|
+3. **页面刷新:**
|
|
|
+ - 创建/删除数据后需要刷新页面或重新导航
|
|
|
+ - 使用 `page.reload()` 或 `goto()` 刷新
|
|
|
+
|
|
|
+4. **选择器优先级:**
|
|
|
+ - 优先使用 data-testid(最稳定)
|
|
|
+ - 其次使用 role + label(较稳定)
|
|
|
+ - 避免使用文本选择器(可能变化)
|
|
|
+
|
|
|
+5. **数据清理顺序:**
|
|
|
+ - 必须遵循外键依赖顺序:子级→父级
|
|
|
+ - 订单→公司→平台
|
|
|
+ - 验证删除成功后再结束测试
|
|
|
+
|
|
|
+6. **API 删除策略(来自 Story 11.2):**
|
|
|
+ - 使用 API 直接删除,绕过 UI 的不可靠性
|
|
|
+ - 删除成功后刷新页面确保列表更新
|
|
|
+
|
|
|
+### 已知问题和注意事项
|
|
|
+
|
|
|
+1. **OrderManagementPage 需要验证:**
|
|
|
+ - 确认 `fillOrderForm` 方法中平台和公司的选择逻辑正确
|
|
|
+ - 确认表单字段的数据-testid 或 label 是否正确
|
|
|
+
|
|
|
+2. **公司选择可能需要先选择平台:**
|
|
|
+ - 根据业务逻辑,CompanySelector 可能需要先选择平台
|
|
|
+ - 需要在测试中验证这个行为
|
|
|
+
|
|
|
+3. **测试数据唯一性:**
|
|
|
+ - 使用时间戳确保唯一性
|
|
|
+ - 避免不同测试之间的数据冲突
|
|
|
+
|
|
|
+4. **配置数据在列表中的显示:**
|
|
|
+ - 需要验证订单列表中平台和公司列的显示
|
|
|
+ - 可能需要滚动列表才能看到某些列
|
|
|
+
|
|
|
+### Epic 11 完成标准
|
|
|
+
|
|
|
+**Epic 11 回顾:**
|
|
|
+- ✅ Story 11.1: Platform Page Object
|
|
|
+- ✅ Story 11.2: 创建测试平台
|
|
|
+- ✅ Story 11.3: 验证平台列表显示
|
|
|
+- ✅ Story 11.4: Company Page Object
|
|
|
+- ✅ Story 11.5: 创建测试公司
|
|
|
+- ✅ Story 11.6: 验证公司列表显示
|
|
|
+- ✅ Story 11.7: Channel Page Object
|
|
|
+- ✅ Story 11.8: 创建测试渠道
|
|
|
+- 🔄 Story 11.9: 配置数据验证(当前)
|
|
|
+
|
|
|
+**Epic 11 完成条件:**
|
|
|
+1. 所有 Platform、Company、Channel 的 CRUD 测试完成
|
|
|
+2. 验证订单可以使用配置数据(平台和公司)
|
|
|
+3. 为后续 Epic(订单管理、用户管理)提供稳定的测试数据
|
|
|
+
|
|
|
+### References
|
|
|
+
|
|
|
+- [Epic 11 基础配置管理测试](../planning-artifacts/epics.md#epic-11-基础配置管理测试-epic-f)
|
|
|
+- [Story 11.2 平台创建测试](./11-2-platform-create-test.story.md) - 参考测试模式
|
|
|
+- [Story 11.5 公司创建测试](./11-5-company-create-test.story.md) - 参考测试模式
|
|
|
+- [OrderManagementPage](../../web/tests/e2e/pages/admin/order-management.page.ts) - 使用此 Page Object
|
|
|
+- [PlatformManagementPage](../../web/tests/e2e/pages/admin/platform-management.page.ts) - 用于创建测试平台
|
|
|
+- [CompanyManagementPage](../../web/tests/e2e/pages/admin/company-management.page.ts) - 用于创建测试公司
|
|
|
+- [测试标准](../../docs/standards/testing-standards.md)
|
|
|
+- [Web UI 测试标准](../../docs/standards/web-ui-testing-standards.md)
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+
|
|
|
+Claude (d8d-model)
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+
|
|
|
+无特殊问题需要记录。Story 创建过程顺利。
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+
|
|
|
+**Story 创建完成:**
|
|
|
+1. ✅ 分析 Story 11.9 需求:验证订单可以选择平台和公司
|
|
|
+2. ✅ 创建完整的 Story 文档
|
|
|
+3. ✅ 包含所有验收标准和任务分解
|
|
|
+4. ✅ 提供详细的 Dev Notes 指导开发者
|
|
|
+5. ✅ 参考 Story 11.2 和 11.5 的测试模式
|
|
|
+6. ✅ 分析 OrderManagementPage 的 API 和方法
|
|
|
+7. ✅ 提供完整的测试用例示例
|
|
|
+8. ✅ 说明数据清理策略(订单→公司→平台)
|
|
|
+9. ✅ 强调异步 Select 的处理方式
|
|
|
+10. ✅ 设置状态为 ready-for-dev
|
|
|
+
|
|
|
+**文档包含内容:**
|
|
|
+- Epic 11 背景和目标
|
|
|
+- 架构模式和约束
|
|
|
+- OrderManagementPage API 参考
|
|
|
+- 创建订单表单分析
|
|
|
+- 完整的测试用例设计
|
|
|
+- 数据清理策略
|
|
|
+- PlatformSelector 和 CompanySelector 集成要点
|
|
|
+- 项目结构约束
|
|
|
+- 测试标准和规范
|
|
|
+- 前序 Story 关键经验
|
|
|
+- Epic 11 完成标准
|
|
|
+
|
|
|
+### File List
|
|
|
+
|
|
|
+**新增文件:**
|
|
|
+- `_bmad-output/implementation-artifacts/11-9-config-data-validation.md` - 本 story 文件
|
|
|
+
|
|
|
+**依赖的已有文件:**
|
|
|
+- `web/tests/e2e/pages/admin/order-management.page.ts` - 订单管理 Page Object(已存在)
|
|
|
+- `web/tests/e2e/pages/admin/platform-management.page.ts` - Story 11.1 创建
|
|
|
+- `web/tests/e2e/pages/admin/company-management.page.ts` - Story 11.4 创建
|
|
|
+- `web/tests/e2e/utils/test-setup.ts` - 测试夹具配置
|
|
|
+
|
|
|
+**将要创建的文件:**
|
|
|
+- `web/tests/e2e/specs/admin/order-config-validation.spec.ts` - 订单配置验证 E2E 测试
|