# Story 11.6: 验证公司列表显示

Status: done

<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->

## 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`
