Status: done
作为测试开发者, 我想要验证订单可以选择平台和公司配置数据, 以便确保 Epic 11 的配置管理测试为后续的订单管理测试提供稳定的测试数据基础。
AC1: 创建测试文件
web/tests/e2e/specs/admin/order-config-validation.spec.tsOrderManagementPage Page ObjectAC2: 验证订单可以选择平台
selectRadixOptionAsync 选择平台AC3: 验证订单可以选择公司
selectRadixOptionAsync 选择公司AC4: 验证平台和公司的关联关系
AC5: 验证配置数据在订单列表中正确显示
AC6: 测试数据清理
AC7: 代码质量标准
[ ] 任务 1: 创建测试文件和基础结构 (AC: 1, 7)
web/tests/e2e/specs/admin/order-config-validation.spec.ts[ ] 任务 2: 实现测试前置条件 (AC: 1, 2)
test.beforeEach() 登录后台[ ] 任务 3: 实现订单选择平台验证 (AC: 2, 6)
selectRadixOptionAsync 选择平台[ ] 任务 4: 实现订单选择公司验证 (AC: 3, 6)
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-validationEpic 11: 基础配置管理测试 (Epic F)
为平台、公司、渠道配置管理编写 E2E 测试,为后续用户管理和跨端测试提供必要的测试数据。
实体关系链:
Platform (平台)
↓ 1:N
Company (公司) - 必须 platformId
↓ 1:N
Order (订单) - 必须 companyId
↓
Channel (渠道) - 订单的可选条件
Story 11.9 在 Epic 中的位置:
测试文件结构参考:
参考 Story 11.2(平台创建测试)和 Story 11.5(公司创建测试)的结构模式:
web/tests/e2e/specs/admin/order-config-validation.spec.ts(当前)标准测试文件结构:
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 已添加:
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));
},
});
相关方法:
| 方法 | 描述 | 返回值 |
|---|---|---|
goto() |
导航到订单管理页面 | Promise<void> |
openCreateDialog() |
打开创建订单对话框 | Promise<void> |
fillOrderForm(data) |
填写订单表单 | Promise<void> |
createOrder(data) |
创建订单(完整流程) | Promise<FormSubmitResult> |
orderExists(name) |
验证订单是否存在 | Promise<boolean> |
deleteOrder(name) |
删除订单 | Promise<boolean> |
数据接口:
interface OrderData {
name: string; // 订单名称(必填)
expectedStartDate?: string; // 预计开始日期
platformName?: string; // 平台名称
companyName?: string; // 公司名称
channelName?: string; // 渠道名称
status?: OrderStatus; // 订单状态
workStatus?: WorkStatus; // 工作状态
}
订单创建对话框字段(来自 OrderManagement.tsx):
name - Input(必填)
platformId - PlatformSelector(异步)
selectRadixOptionAsync 选择companyId - CompanySelector(异步)
selectRadixOptionAsync 选择expectedStartDate - DateInput(可选)
按钮:
测试用例 1: 验证订单可以选择平台
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: 验证订单可以选择公司
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: 验证平台和公司关联关系
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: 验证订单列表显示配置数据
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);
});
遵循外键依赖顺序:
订单 → 公司 → 平台
原因:
清理示例:
test.afterEach(async ({ orderManagementPage, companyManagementPage, platformManagementPage }) => {
// 按相反顺序清理
if (orderName) {
await orderManagementPage.deleteOrder(orderName);
}
if (companyName) {
await companyManagementPage.deleteCompany(companyName);
}
if (platformName) {
await platformManagementPage.deletePlatform(platformName);
}
});
使用 @d8d/e2e-test-utils 的 selectRadixOptionAsync:
import { selectRadixOptionAsync } from '@d8d/e2e-test-utils';
// 选择平台
await selectRadixOptionAsync(orderManagementPage.page, '平台', platformName);
// 选择公司
await selectRadixOptionAsync(orderManagementPage.page, '公司', companyName);
异步加载等待:
selectRadixOptionAsync 确保选项加载完成测试文件存放路径:
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运行单个测试文件:
cd web
pnpm test:e2e:chromium order-config-validation.spec.ts
运行单个测试用例:
cd web
pnpm test:e2e:chromium order-config-validation.spec.ts -g "应该成功选择平台"
快速失败模式(调试):
cd web
timeout 60 pnpm test:e2e:chromium order-config-validation.spec.ts
Epic 11 内部依赖:
外部依赖:
@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.mddocs/standards/web-ui-testing-standards.md关键测试原则:
从 Story 11.1-11.8 中学到的关键经验:
异步 Select 处理:
selectRadixOptionAsync测试数据要求:
页面刷新:
page.reload() 或 goto() 刷新选择器优先级:
数据清理顺序:
API 删除策略(来自 Story 11.2):
OrderManagementPage 需要验证:
fillOrderForm 方法中平台和公司的选择逻辑正确公司选择可能需要先选择平台:
测试数据唯一性:
配置数据在列表中的显示:
Epic 11 回顾:
Epic 11 完成条件:
Claude (d8d-model)
无特殊问题需要记录。Story 创建过程顺利。
Story 创建完成:
Story 实现完成:
web/tests/e2e/specs/admin/order-config-validation.spec.ts实现过程中的关键修复:
问题1: 初始使用 selectRadixOption 工具函数无法正确找到平台选择器
selectRadixOption 尝试查找 [data-testid="${label}-trigger"],但订单表单中的平台选择器使用的是不同的 DOM 结构dialog.getByText('平台').first().locator('..').getByRole('combobox').first() 来定位平台选择器问题2: getByText('平台') 匹配到列表表头而不是对话框内的标签
dialog.getByText('平台') 限定在对话框内查找问题3: AC5 测试使用 orderManagementPage.createOrder() 方法超时
OrderManagementPage.fillOrderForm 方法使用 selectRadixOption 工具函数导致超时问题4: 清理策略测试中 companyExists 返回 false
文档包含内容:
新增文件(已创建):
_bmad-output/implementation-artifacts/11-9-config-data-validation.md - 本 story 文件web/tests/e2e/specs/admin/order-config-validation.spec.ts - 订单配置验证 E2E 测试依赖的已有文件:
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 - 测试夹具配置