|
@@ -0,0 +1,391 @@
|
|
|
|
|
+# Story 11.2: 创建测试平台
|
|
|
|
|
+
|
|
|
|
|
+Status: ready-for-dev
|
|
|
|
|
+
|
|
|
|
|
+<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
|
|
|
|
|
+
|
|
|
|
|
+## Story
|
|
|
|
|
+
|
|
|
|
|
+作为测试开发者,
|
|
|
|
|
+我想要编写平台创建功能的 E2E 测试,
|
|
|
|
|
+以便验证平台管理模块的创建功能正常工作。
|
|
|
|
|
+
|
|
|
|
|
+## Acceptance Criteria
|
|
|
|
|
+
|
|
|
|
|
+1. **AC1: 创建测试文件**
|
|
|
|
|
+ - 文件路径: `web/tests/e2e/specs/admin/platform-create.spec.ts`
|
|
|
|
|
+ - 使用 Playwright test 框架
|
|
|
|
|
+ - 使用 Story 11.1 创建的 `PlatformManagementPage` Page Object
|
|
|
|
|
+ - 定义测试夹具(fixtures)包含 Page Object
|
|
|
|
|
+
|
|
|
|
|
+2. **AC2: 测试基本创建流程**
|
|
|
|
|
+ - 导航到平台管理页面
|
|
|
|
|
+ - 点击创建平台按钮
|
|
|
|
|
+ - 填写平台名称(必填字段)
|
|
|
|
|
+ - 提交表单
|
|
|
|
|
+ - 验证创建成功(Toast 消息 + 列表中显示新平台)
|
|
|
|
|
+
|
|
|
|
|
+3. **AC3: 测试完整表单字段**
|
|
|
|
|
+ - 填写所有字段(平台名称、联系人、联系电话、联系邮箱)
|
|
|
|
|
+ - 验证所有数据保存正确
|
|
|
|
|
+ - 验证平台出现在列表中
|
|
|
|
|
+
|
|
|
|
|
+4. **AC4: 测试表单验证**
|
|
|
|
|
+ - 未填写平台名称时提交
|
|
|
|
|
+ - 验证错误提示显示
|
|
|
|
|
+ - 验证平台未被创建
|
|
|
|
|
+
|
|
|
|
|
+5. **AC5: 测试数据唯一性**
|
|
|
|
|
+ - 创建平台时使用时间戳确保平台名称唯一
|
|
|
|
|
+ - 验证不同测试之间数据不冲突
|
|
|
|
|
+
|
|
|
|
|
+6. **AC6: 代码质量标准**
|
|
|
|
|
+ - 通过 ESLint 检查,无警告和错误
|
|
|
|
|
+ - 通过 TypeScript 类型检查
|
|
|
|
|
+ - 测试用例有清晰的描述
|
|
|
|
|
+
|
|
|
|
|
+## Tasks / Subtasks
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 1: 创建测试文件和基础结构 (AC: 1, 6)
|
|
|
|
|
+ - [ ] 创建文件 `web/tests/e2e/specs/admin/platform-create.spec.ts`
|
|
|
|
|
+ - [ ] 导入 Playwright test 和 PlatformManagementPage
|
|
|
|
|
+ - [ ] 定义测试夹具(adminLoginPage, platformManagementPage)
|
|
|
|
|
+ - [ ] 设置测试基础配置(timeout 等)
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 2: 实现测试前置条件 (AC: 1, 2)
|
|
|
|
|
+ - [ ] 实现 `test.beforeEach()` 登录后台
|
|
|
|
|
+ - [ ] 导航到平台管理页面
|
|
|
|
|
+ - [ ] 验证页面加载完成
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 3: 实现基本创建流程测试 (AC: 2, 5)
|
|
|
|
|
+ - [ ] 编写测试用例:应该成功创建平台(仅填写平台名称)
|
|
|
|
|
+ - [ ] 使用时间戳生成唯一平台名称
|
|
|
|
|
+ - [ ] 验证 Toast 成功消息
|
|
|
|
|
+ - [ ] 验证平台出现在列表中
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 4: 实现完整表单字段测试 (AC: 3, 5)
|
|
|
|
|
+ - [ ] 编写测试用例:应该成功创建平台(填写所有字段)
|
|
|
|
|
+ - [ ] 填写平台名称、联系人、联系电话、联系邮箱
|
|
|
|
|
+ - [ ] 验证所有数据保存正确
|
|
|
|
|
+ - [ ] 验证平台出现在列表中
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 5: 实现表单验证测试 (AC: 4)
|
|
|
|
|
+ - [ ] 编写测试用例:未填写平台名称时应显示错误
|
|
|
|
|
+ - [ ] 尝试提交空表单
|
|
|
|
|
+ - [ ] 验证错误 Toast 消息显示
|
|
|
|
|
+ - [ ] 验证平台未被创建
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 6: 实现测试后清理 (AC: 5)
|
|
|
|
|
+ - [ ] 实现 `test.afterEach()` 清理测试数据
|
|
|
|
|
+ - [ ] 删除测试创建的平台
|
|
|
|
|
+ - [ ] 验证清理成功
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务 7: 运行测试并验证 (AC: 2, 3, 4, 6)
|
|
|
|
|
+ - [ ] 运行测试: `pnpm test:e2e:chromium platform-create.spec.ts`
|
|
|
|
|
+ - [ ] 验证所有测试通过
|
|
|
|
|
+ - [ ] 修复发现的问题
|
|
|
|
|
+ - [ ] 运行 ESLint 和 TypeScript 检查
|
|
|
|
|
+
|
|
|
|
|
+## Dev Notes
|
|
|
|
|
+
|
|
|
|
|
+### Epic 11 背景和目标
|
|
|
|
|
+
|
|
|
|
|
+**Epic 11: 基础配置管理测试 (Epic F)**
|
|
|
|
|
+
|
|
|
|
|
+为平台、公司、渠道配置管理编写 E2E 测试,为后续用户管理和跨端测试提供必要的测试数据。
|
|
|
|
|
+
|
|
|
|
|
+**实体关系链:**
|
|
|
|
|
+```
|
|
|
|
|
+Platform (平台)
|
|
|
|
|
+ ↓ 1:N
|
|
|
|
|
+Company (公司) - 必须 platformId
|
|
|
|
|
+ ↓ 1:N
|
|
|
|
|
+Order (订单) - 必须 companyId
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Story 11.2 在 Epic 中的位置:**
|
|
|
|
|
+- Story 11.1 (已完成) → Story 11.2 (当前) → Story 11.3 → ...
|
|
|
|
|
+- Story 11.1 创建了 PlatformManagementPage Page Object
|
|
|
|
|
+- Story 11.2 编写平台创建功能的 E2E 测试
|
|
|
|
|
+- Story 11.3 将编写平台列表显示验证测试
|
|
|
|
|
+
|
|
|
|
|
+### 架构模式和约束
|
|
|
|
|
+
|
|
|
|
|
+**测试文件结构参考:**
|
|
|
|
|
+
|
|
|
|
|
+参考现有测试文件的结构模式:
|
|
|
|
|
+- `web/tests/e2e/specs/admin/order-create.spec.ts`
|
|
|
|
|
+- `web/tests/e2e/specs/admin/disability-person-crud.spec.ts`
|
|
|
|
|
+
|
|
|
|
|
+**标准测试文件结构:**
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { test, expect } from '@playwright/test';
|
|
|
|
|
+import { PlatformManagementPage } from '../../pages/admin/platform-management.page';
|
|
|
|
|
+
|
|
|
|
|
+test.describe('平台创建功能', () => {
|
|
|
|
|
+ test.beforeEach(async ({ adminLoginPage, platformManagementPage }) => {
|
|
|
|
|
+ // 登录后台
|
|
|
|
|
+ await adminLoginPage.goto();
|
|
|
|
|
+ await adminLoginPage.login('admin', 'admin123');
|
|
|
|
|
+
|
|
|
|
|
+ // 导航到平台管理页面
|
|
|
|
|
+ await platformManagementPage.goto();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ test.afterEach(async ({ platformManagementPage }) => {
|
|
|
|
|
+ // 清理测试数据
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ test('应该成功创建平台', async ({ platformManagementPage }) => {
|
|
|
|
|
+ // 测试逻辑
|
|
|
|
|
+ });
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**测试夹具配置:**
|
|
|
|
|
+
|
|
|
|
|
+需要确保测试夹具在 `web/tests/e2e/fixtures.ts` 中定义:
|
|
|
|
|
+```typescript
|
|
|
|
|
+export const test = test.extend<{
|
|
|
|
|
+ adminLoginPage: AdminLoginPage;
|
|
|
|
|
+ platformManagementPage: PlatformManagementPage;
|
|
|
|
|
+}>({
|
|
|
|
|
+ adminLoginPage: async ({ page }, use) => {
|
|
|
|
|
+ await use(new AdminLoginPage(page));
|
|
|
|
|
+ },
|
|
|
|
|
+ platformManagementPage: async ({ page }, use) => {
|
|
|
|
|
+ await use(new PlatformManagementPage(page));
|
|
|
|
|
+ },
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### PlatformManagementPage API 参考
|
|
|
|
|
+
|
|
|
|
|
+**来自 Story 11.1 的可用方法:**
|
|
|
|
|
+
|
|
|
|
|
+| 方法 | 描述 | 返回值 |
|
|
|
|
|
+|------|------|--------|
|
|
|
|
|
+| `goto()` | 导航到平台管理页面 | `Promise<void>` |
|
|
|
|
|
+| `createPlatform(data)` | 创建平台(完整流程) | `Promise<FormSubmitResult>` |
|
|
|
|
|
+| `editPlatform(name, data)` | 编辑平台 | `Promise<FormSubmitResult>` |
|
|
|
|
|
+| `deletePlatform(name)` | 删除平台 | `Promise<boolean>` |
|
|
|
|
|
+| `platformExists(name)` | 验证平台是否存在 | `Promise<boolean>` |
|
|
|
|
|
+
|
|
|
|
|
+**数据接口:**
|
|
|
|
|
+```typescript
|
|
|
|
|
+interface PlatformData {
|
|
|
|
|
+ platformName: string; // 必填
|
|
|
|
|
+ contactPerson?: string;
|
|
|
|
|
+ contactPhone?: string;
|
|
|
|
|
+ contactEmail?: string;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface FormSubmitResult {
|
|
|
|
|
+ success: boolean;
|
|
|
|
|
+ hasError: boolean;
|
|
|
|
|
+ hasSuccess: boolean;
|
|
|
|
|
+ errorMessage?: string;
|
|
|
|
|
+ successMessage?: string;
|
|
|
|
|
+ responses?: NetworkResponse[];
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 项目结构约束
|
|
|
|
|
+
|
|
|
|
|
+**测试文件存放路径:**
|
|
|
|
|
+```
|
|
|
|
|
+web/tests/e2e/specs/admin/
|
|
|
|
|
+├── order-*.spec.ts # 订单管理测试(参考)
|
|
|
|
|
+├── disability-person-*.spec.ts # 残疾人管理测试(参考)
|
|
|
|
|
+└── platform-create.spec.ts # 平台创建测试(本次创建)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 测试用例设计
|
|
|
|
|
+
|
|
|
|
|
+**测试用例 1: 基本创建流程(仅必填字段)**
|
|
|
|
|
+```typescript
|
|
|
|
|
+test('应该成功创建平台(仅填写平台名称)', async ({ platformManagementPage }) => {
|
|
|
|
|
+ const timestamp = Date.now();
|
|
|
|
|
+ const platformName = `测试平台_${timestamp}`;
|
|
|
|
|
+
|
|
|
|
|
+ // 创建平台
|
|
|
|
|
+ const result = await platformManagementPage.createPlatform({
|
|
|
|
|
+ platformName,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 验证创建成功
|
|
|
|
|
+ expect(result.success).toBe(true);
|
|
|
|
|
+ expect(result.hasSuccess).toBe(true);
|
|
|
|
|
+
|
|
|
|
|
+ // 验证平台出现在列表中
|
|
|
|
|
+ const exists = await platformManagementPage.platformExists(platformName);
|
|
|
|
|
+ expect(exists).toBe(true);
|
|
|
|
|
+
|
|
|
|
|
+ // 清理
|
|
|
|
|
+ await platformManagementPage.deletePlatform(platformName);
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**测试用例 2: 完整表单字段**
|
|
|
|
|
+```typescript
|
|
|
|
|
+test('应该成功创建平台(填写所有字段)', async ({ platformManagementPage }) => {
|
|
|
|
|
+ const timestamp = Date.now();
|
|
|
|
|
+ const platformName = `完整测试平台_${timestamp}`;
|
|
|
|
|
+ const contactPerson = `测试联系人_${timestamp}`;
|
|
|
|
|
+ const contactPhone = '13800138000';
|
|
|
|
|
+ const contactEmail = `test_${timestamp}@example.com`;
|
|
|
|
|
+
|
|
|
|
|
+ // 创建平台
|
|
|
|
|
+ const result = await platformManagementPage.createPlatform({
|
|
|
|
|
+ platformName,
|
|
|
|
|
+ contactPerson,
|
|
|
|
|
+ contactPhone,
|
|
|
|
|
+ contactEmail,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 验证创建成功
|
|
|
|
|
+ expect(result.success).toBe(true);
|
|
|
|
|
+
|
|
|
|
|
+ // 验证平台出现在列表中
|
|
|
|
|
+ const exists = await platformManagementPage.platformExists(platformName);
|
|
|
|
|
+ expect(exists).toBe(true);
|
|
|
|
|
+
|
|
|
|
|
+ // 清理
|
|
|
|
|
+ await platformManagementPage.deletePlatform(platformName);
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**测试用例 3: 表单验证(空平台名称)**
|
|
|
|
|
+```typescript
|
|
|
|
|
+test('未填写平台名称时应显示错误', async ({ platformManagementPage }) => {
|
|
|
|
|
+ const timestamp = Date.now();
|
|
|
|
|
+
|
|
|
|
|
+ // 打开创建对话框
|
|
|
|
|
+ await platformManagementPage.openCreateDialog();
|
|
|
|
|
+
|
|
|
|
|
+ // 不填写任何字段,直接提交
|
|
|
|
|
+ const result = await platformManagementPage.submitForm();
|
|
|
|
|
+
|
|
|
|
|
+ // 验证显示错误
|
|
|
|
|
+ expect(result.hasError).toBe(true);
|
|
|
|
|
+ expect(result.errorMessage).toContain('平台名称');
|
|
|
|
|
+
|
|
|
|
|
+ // 关闭对话框
|
|
|
|
|
+ await platformManagementPage.cancelDialog();
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 数据唯一性策略
|
|
|
|
|
+
|
|
|
|
|
+**使用时间戳确保唯一性:**
|
|
|
|
|
+```typescript
|
|
|
|
|
+const timestamp = Date.now();
|
|
|
|
|
+const uniqueId = `platform_test_${timestamp}`;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**测试数据清理:**
|
|
|
|
|
+- 每个测试用例结束后清理自己创建的数据
|
|
|
|
|
+- 使用 `test.afterEach()` 作为兜底清理机制
|
|
|
|
|
+- 如果测试失败,记录未清理的平台名称供手动清理
|
|
|
|
|
+
|
|
|
|
|
+### 测试运行命令
|
|
|
|
|
+
|
|
|
|
|
+**运行单个测试文件:**
|
|
|
|
|
+```bash
|
|
|
|
|
+cd web
|
|
|
|
|
+pnpm test:e2e:chromium platform-create.spec.ts
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**运行单个测试用例:**
|
|
|
|
|
+```bash
|
|
|
|
|
+cd web
|
|
|
|
|
+pnpm test:e2e:chromium platform-create.spec.ts -g "应该成功创建平台"
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**快速失败模式(调试):**
|
|
|
|
|
+```bash
|
|
|
|
|
+cd web
|
|
|
|
|
+timeout 60 pnpm test:e2e:chromium platform-create.spec.ts
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 依赖关系
|
|
|
|
|
+
|
|
|
|
|
+**Epic 11 内部依赖:**
|
|
|
|
|
+- Story 11.1: ✅ 已完成(PlatformManagementPage)
|
|
|
|
|
+- Story 11.2: 当前(编写平台创建测试)
|
|
|
|
|
+- Story 11.3: 平台列表显示验证(依赖当前 Story)
|
|
|
|
|
+
|
|
|
|
|
+**外部依赖:**
|
|
|
|
|
+- Epic 1, 2: `@d8d/e2e-test-utils` 包(已存在)
|
|
|
|
|
+- `web/tests/e2e/fixtures.ts`: 需要包含 platformManagementPage 夹具
|
|
|
|
|
+
|
|
|
|
|
+### 测试标准和规范
|
|
|
|
|
+
|
|
|
|
|
+遵循项目测试标准:
|
|
|
|
|
+- `docs/standards/testing-standards.md`
|
|
|
|
|
+- `docs/standards/web-ui-testing-standards.md`
|
|
|
|
|
+
|
|
|
|
|
+**关键测试原则:**
|
|
|
|
|
+1. 测试独立性:每个测试用例独立运行,不依赖其他测试
|
|
|
|
|
+2. 数据清理:每个测试结束后清理自己创建的数据
|
|
|
|
|
+3. 清晰断言:使用 expect() 明确断言预期结果
|
|
|
|
|
+4. 等待策略:使用 Playwright 的 auto-waiting,必要时使用 waitFor()
|
|
|
|
|
+
|
|
|
|
|
+### 已知问题和注意事项
|
|
|
|
|
+
|
|
|
|
|
+1. **测试夹具配置:**
|
|
|
|
|
+ - 确保 `platformManagementPage` 夹具在 `fixtures.ts` 中定义
|
|
|
|
|
+ - 参考 `adminLoginPage` 的配置方式
|
|
|
|
|
+
|
|
|
|
|
+2. **登录状态:**
|
|
|
|
|
+ - 测试前需要登录后台
|
|
|
|
|
+ - 使用 `adminLoginPage.login('admin', 'admin123')`
|
|
|
|
|
+
|
|
|
|
|
+3. **页面导航:**
|
|
|
|
|
+ - 平台管理页面路径: `/admin/platforms`
|
|
|
|
|
+ - 确保页面加载完成后再进行操作
|
|
|
|
|
+
|
|
|
|
|
+4. **数据清理:**
|
|
|
|
|
+ - 使用 `deletePlatform()` 方法删除测试数据
|
|
|
|
|
+ - 验证删除成功后再结束测试
|
|
|
|
|
+
|
|
|
|
|
+### 开发顺序建议
|
|
|
|
|
+
|
|
|
|
|
+1. 首先创建测试文件和基础结构
|
|
|
|
|
+2. 配置测试夹具(如需要)
|
|
|
|
|
+3. 实现测试前置条件(登录、导航)
|
|
|
|
|
+4. 实现基本创建流程测试
|
|
|
|
|
+5. 实现完整表单字段测试
|
|
|
|
|
+6. 实现表单验证测试
|
|
|
|
|
+7. 实现测试后清理
|
|
|
|
|
+8. 运行测试并验证
|
|
|
|
|
+9. 代码质量检查(ESLint、TypeScript)
|
|
|
|
|
+
|
|
|
|
|
+### Page Object 完整路径
|
|
|
|
|
+
|
|
|
|
|
+**文件路径:**
|
|
|
|
|
+`web/tests/e2e/pages/admin/platform-management.page.ts`
|
|
|
|
|
+
|
|
|
|
|
+**导入语句:**
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { PlatformManagementPage } from '../../pages/admin/platform-management.page';
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Dev Agent Record
|
|
|
|
|
+
|
|
|
|
|
+### Agent Model Used
|
|
|
|
|
+
|
|
|
|
|
+Claude (d8d-model)
|
|
|
|
|
+
|
|
|
|
|
+### Debug Log References
|
|
|
|
|
+
|
|
|
|
|
+无(初始创建)
|
|
|
|
|
+
|
|
|
|
|
+### Completion Notes List
|
|
|
|
|
+
|
|
|
|
|
+待开发
|
|
|
|
|
+
|
|
|
|
|
+### File List
|
|
|
|
|
+
|
|
|
|
|
+待创建文件:
|
|
|
|
|
+- `web/tests/e2e/specs/admin/platform-create.spec.ts`
|