# Story 11.6: 验证公司列表显示 Status: done ## Story 作为测试开发者, 我想要编写公司列表查看的 E2E 测试, 以便验证公司列表的基本功能和数据展示。 ## Acceptance Criteria **Given** Epic 11.4 (Company 管理 Page Object) 已完成 **When** 编写公司列表查看测试用例 **Then** 验证以下场景: 1. **公司列表按预期加载** - 页面成功导航到 `/admin/companies` - 页面标题"公司管理"显示正确 - 表格组件加载并可见 - 表格数据成功渲染 2. **公司数据的正确展示** - 公司名称显示正确(第0列) - 关联平台显示正确(第1列) - 联系人显示正确(第2列) - 联系电话显示正确(第3列) - 状态徽章显示正确(第4列:启用/禁用) - 创建时间显示正确(第5列) - 操作按钮显示正确(第6列:编辑、删除) 3. **列表功能验证** - 创建公司按钮存在且可点击 - 搜索输入框存在 - 搜索按钮存在 - 当无数据时显示正确提示 - 表格分页功能正常(如适用) 4. **测试在真实浏览器中通过** - 使用 Playwright Chromium 运行 - 所有断言通过 - 无超时失败 ## Tasks / Subtasks - [x] Task 1: 创建测试文件基础结构 (AC: #1) - [x] Subtask 1.1: 创建 `web/tests/e2e/specs/admin/company-list.spec.ts` - [x] Subtask 1.2: 导入必要的依赖和 Page Object - [x] Subtask 1.3: 配置测试 fixture - [x] Task 2: 实现页面加载和基础验证测试 (AC: #1) - [x] Subtask 2.1: 测试 - 应该成功导航到公司管理页面 - [x] Subtask 2.2: 测试 - 应该显示正确的页面标题 - [x] Subtask 2.3: 测试 - 应该加载公司列表表格 - [x] Task 3: 实现数据显示验证测试 (AC: #2) - [x] Subtask 3.1: 测试 - 应该正确显示公司名称 - [x] Subtask 3.2: 测试 - 应该正确显示关联平台 - [x] Subtask 3.3: 测试 - 应该正确显示联系人信息 - [x] Subtask 3.4: 测试 - 应该正确显示状态徽章 - [x] Subtask 3.5: 测试 - 应该正确显示创建时间 - [x] Task 4: 实现列表功能测试 (AC: #3, #4) - [x] Subtask 4.1: 测试 - 应该显示创建公司按钮 - [x] Subtask 4.2: 测试 - 应该显示搜索输入框 - [x] Subtask 4.3: 测试 - 无数据时显示正确提示 - [x] Subtask 4.4: 运行所有测试并验证通过 ## Code Review Follow-ups (AI) 本代码审查由 AI 对抗性代码审查工作流执行,于 2026-01-12 完成。 ### 发现并修复的问题 **HIGH 问题(已修复):** 1. **测试数据隔离问题** - 添加了 `beforeEach`/`afterEach` 钩子 - 每个测试运行前创建唯一的测试数据 - 测试完成后自动清理数据 - 修复了测试依赖外部数据导致的假通过问题 2. **空数据提示测试虚假** - 重写了无数据提示测试 - 原测试只验证表格存在,不验证空状态 - 新测试搜索不存在的公司,验证空数据行为 3. **测试静默通过** - 移除了 `if (count > 0)` 模式 - 原代码数据为空时测试通过但不验证任何内容 - 新代码使用 `filter({ hasText })` 精确匹配,数据不存在会抛出清晰错误 **MEDIUM 问题(已修复):** 4. **冗余 count() 调用** - 简化了测试代码 - 移除了 `first().count()` 冗余检查 - 直接使用 `expect().toBeVisible()` 验证 5. **搜索功能未测试** - 添加了实际搜索测试 - 原测试只验证搜索框存在 - 新测试实际执行搜索并验证结果 6. **分页功能未测试** - 添加了分页控件检查 - 检测分页控件是否存在 - 如不存在,验证至少有数据在表格中 7. **代码质量改进** - 添加了常量定义 - 定义 `TABLE_COLUMNS` 常量避免魔法数字 - 定义 `generateTestName()` 函数生成唯一测试数据 **LOW 问题(已修复):** 8. **测试描述优化** - 合并了搜索相关测试 ### 测试结果 - 初始测试: 12 passed (原始实现) - 代码审查后: 14 passed (包含新增的搜索和空数据测试) - 所有 HIGH 和 MEDIUM 问题已修复 ### 遗留建议 1. **Page Object 选择器改进建议**: 建议在 UI 组件上添加 `data-testid="company-page-title"` 而非依赖 `data-slot="card-title"`,以提高选择器稳定性 ## Dev Notes ### Epic 上下文 **Epic 11: 基础配置管理测试 (Epic F)** **目标:** 为平台、公司、渠道配置管理编写 E2E 测试,为后续用户管理和跨端测试提供必要的测试数据。 **实体关系链:** ``` Platform (平台) ↓ 1:N Company (公司) - 必须 platformId ↓ 1:N Order (订单) - 必须 companyId ``` **当前进度:** - 11.1: Platform 管理 Page Object ✅ done - 11.2: 创建测试平台 ✅ done - 11.3: 验证平台列表显示 ✅ done - 11.4: Company 管理 Page Object ✅ done - 11.5: 创建测试公司 backlog - **11.6: 验证公司列表显示** ← 当前故事 - 11.7-11.9: 后续故事 ### 前序故事学习 (Story 11.4) **Story 11.4 (Company Page Object) 已完成:** - Page Object 文件: `web/tests/e2e/pages/admin/company-management.page.ts` - 完整的选择器定义和 CRUD 方法 - 使用 `@d8d/e2e-test-utils` 的 `selectRadixOptionAsync` - 支持创建、编辑、删除、搜索功能 - 包含完整的 TypeScript 类型定义 **关键 API:** ```typescript // 导航到页面 await companyPage.goto(); // 验证页面可见 await companyPage.expectToBeVisible(); // 检查公司是否存在 const exists = await companyPage.companyExists('公司名称'); // 创建公司 const result = await companyPage.createCompany({ companyName: '测试公司', contactPerson: '张三', contactPhone: '13800138000' }, '平台名称'); ``` **表格列顺序(重要):** - 第0列: 公司名称 - 第1列: 平台 - 第2列: 联系人 - 第3列: 联系电话 - 第4列: 状态(启用/禁用) - 第5列: 创建时间 - 第6列: 操作(编辑、删除) ### 参考测试模式 (Epic 8 区域管理) 参考 `web/tests/e2e/specs/admin/region-list.spec.ts` 的测试模式: 1. **测试文件结构:** ```typescript import { test, expect } from '@playwright/test'; import { CompanyManagementPage } from '@/pages/admin/company-management.page'; test.describe('公司列表管理', () => { let companyPage: CompanyManagementPage; test.beforeEach(async ({ adminLoginPage, page }) => { // 登录 await adminLoginPage.goto(); await adminLoginPage.login('admin', 'admin123'); companyPage = new CompanyManagementPage(page); }); test.afterEach(async ({ companyPage }) => { // 清理测试数据 }); test('应该成功加载公司列表页面', async () => { await companyPage.goto(); // 验证... }); }); ``` 2. **数据验证模式:** - 使用 `page.locator()` 定位表格元素 - 使用 `filter({ hasText })` 精确匹配行 - 使用 `nth(index)` 定位列 - 使用 `expect().toBeVisible()` 验证可见性 - 使用 `expect().toHaveText()` 验证文本内容 3. **测试隔离:** - 每个测试使用唯一数据(时间戳) - 测试后清理数据 - 避免测试间相互影响 ### 技术约束和最佳实践 **选择器策略(来自 Architecture 文档):** 1. 优先使用 `data-testid` 2. 使用 `role` + `name` 组合 3. 避免使用不稳定的 CSS 类 4. 文本匹配使用 `:text-is()` 精确匹配 **等待策略:** - 使用 Playwright 的 auto-waiting 机制 - 不使用 `waitForTimeout`(除非必要) - 使用 `waitForLoadState('domcontentloaded')` 等待页面加载 - 使用 `waitFor({ state: 'visible' })` 等待元素可见 **错误处理:** - 捕获并记录有用的错误信息 - 使用 `console.debug()` 调试(Vitest 支持) - 失败时自动截图(Playwright 默认) ### 测试数据管理 **测试平台创建(前置条件):** 如果测试需要关联平台,需要先确保测试平台存在: - 可以通过 API 直接创建 - 或使用 Story 11.2 创建的测试平台 **测试数据清理:** ```typescript test.afterEach(async ({ companyPage }) => { // 清理测试创建的公司 const testCompanies = ['测试公司1', '测试公司2']; for (const name of testCompanies) { await companyPage.deleteCompany(name); } }); ``` ### Project Structure Notes **测试文件位置:** ``` web/tests/e2e/ ├── pages/admin/ │ └── company-management.page.ts ← 已存在 ├── specs/admin/ │ └── company-list.spec.ts ← 需要创建 └── fixtures/ └── (测试数据文件) ``` **导入路径:** ```typescript // Page Object 导入 import { CompanyManagementPage } from '@/pages/admin/company-management.page'; // 测试工具导入 import { selectRadixOptionAsync } from '@d8d/e2e-test-utils'; ``` ### References **Epic 文档:** - [Source: _bmad-output/planning-artifacts/epics.md#Epic-11] **架构文档:** - [Source: _bmad-output/planning-artifacts/architecture.md] - TypeScript + Playwright 陷阱部分 - [Source: docs/standards/e2e-radix-testing.md] - Radix UI E2E 测试标准 **前序故事:** - [Source: _bmad-output/implementation-artifacts/11-4-company-page-object.md] - Company Page Object **参考测试实现:** - [Source: web/tests/e2e/specs/admin/region-list.spec.ts] - 区域列表测试参考 **项目上下文:** - [Source: _bmad-output/project-context.md] - 技术栈和规则 ## Dev Agent Record ### Agent Model Used Claude Opus 4.5 (claude-opus-4-5-20251101) ### Debug Log References 无 ### Completion Notes List 1. 创建日期: 2026-01-12 2. Epic 状态: in-progress 3. 前置依赖: Story 11.4 (Company Page Object) 已完成 4. 后续故事: Story 11.7 (Channel Page Object - 可选) 5. **初始实施完成:** - 创建了完整的公司列表 E2E 测试文件 `web/tests/e2e/specs/admin/company-list.spec.ts` - 12 个测试全部通过 - 修复了 CompanyManagement Page Object 中的 pageTitle 选择器(从 `getByRole('heading')` 改为使用 `data-slot="card-title"`) - 修复了操作按钮测试(编辑和删除按钮使用图标,没有文本) 6. **代码审查完成 (2026-01-12):** - 修复了 3 个 HIGH 问题(测试数据隔离、空数据测试、静默通过) - 修复了 4 个 MEDIUM 问题(冗余代码、搜索测试、分页测试、代码质量) - 测试数量从 12 个增加到 14 个 - 所有测试通过 (14/14) - Story 状态更新为 "done" ### File List **已创建/修改的文件:** - `web/tests/e2e/specs/admin/company-list.spec.ts` (新建) - 公司列表 E2E 测试,包含 14 个测试用例 - `web/tests/e2e/pages/admin/company-management.page.ts` (修改) - 修复 pageTitle 选择器 - `_bmad-output/implementation-artifacts/11-6-company-list-test.md` (修改) - 添加代码审查记录 **依赖文件:** - `web/tests/e2e/fixtures/admin-login.fixture.ts` - `packages/e2e-test-utils/src/index.ts` **配置文件:** - `web/tests/e2e/playwright.config.ts`